A Takahashikun, The Strider
往某个方向走1步,那就要在这个方向的对立方向(转180度)往回走1步。那么只要转了是360的倍数,各个方向和其对立方向走的步数是相同的,答案为LCM(x,360)/xLCM(x,360)/xLCM(x,360)/x。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int x;scanf("%d",&x);
printf("%d\n",x/__gcd(x,360)*360/x);
}
B Extension
考虑倒退操作,每次可以删除一行或删除一列,然后给删除的这一行或一列染色。但是方案有重复的,我们规定能删列则删列,否则删行,这样方案数唯一。
设dp[i][j][0/1]dp[i][j][0/1]dp[i][j][0/1]为iii行jjj列,000表示只能删行,111表示行列都可以删。
对于dp[i][j][0]dp[i][j][0]dp[i][j][0]转移到dp[i−1][j][1]dp[i-1][j][1]dp[i−1][j][1]的情况,只有第jjj列有两个以上的黑块的时候,才能只删行,如果只有一个黑怪会遵循优先删列的原则不能删行,那么这个转移的系数就是1,即只能第j列放一个黑怪。
#include<bits/stdc++.h>
using namespace std;
const int N=3005,mod=998244353;
typedef long long ll;
int dp[N][N][2];
int main()
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
if(c>a) dp[c][d][0]=1;
if(d>b) dp[c][d][1]=1;
ll ans=0;
for(int i=c;i>=a;i--)
for(int j=d;j>=b;j--)
{
dp[i][j-1][0]=(dp[i][j-1][0]+(ll)dp[i][j][1]*i)%mod;
dp[i][j-1][1]=(dp[i][j-1][1]+(ll)dp[i][j][1]*i)%mod;
dp[i-1][j][0]=(dp[i-1][j][0]+(ll)dp[i][j][0]*j)%mod;
dp[i-1][j][1]=(dp[i-1][j][1]+(ll)dp[i][j][0])%mod;
if(i==a&&j-1==b)
ans=(ans+(ll)dp[i][j][1]*i)%mod;
if(i-1==a&&j==b)
ans=(ans+(ll)dp[i][j][0]*j)%mod;
}
if(a==c&&b==d) ans=1;
printf("%lld\n",ans);
}
C Shift
设总共有n−1n-1n−1个字符000,那么我们得到了nnn个缝隙,在这nnn个缝隙里放入字符111,就得到了所有方案数。
设dp[i][j][h]dp[i][j][h]dp[i][j][h],前iii个缝隙,共放了jjj个111,进行hhh次操作的方案数。
在任意时候,需要满足j>=sum[i]j>=sum[i]j>=sum[i],因为字符111不能往后扔,只能往前扔。
然后得到了一个看起来O(n4)O(n^4)O(n4)的dpdpdp,但是系数之间的关系,满足i+j=∣S∣,h<=min(k,i)i+j=|S|,h<=min(k,i)i+j=∣S∣,h<=min(k,i),这样我们期望实际的i,j,hi,j,hi,j,h为300/2=150300/2=150300/2=150。又由于j>=sum[i]j>=sum[i]j>=sum[i]的约束,有很多无用的状态,又由于常数非常小,我们期望的时间复杂度变成了O(n3)O(n^3)O(n3)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=305,mod=998244353;
int n,k,m,a[N],sum[N];
int dp[N][N][N];
//dp[i][j][h] 第i个坑,用了j个1,移动了h次的方案数
char s[N];
int main()
{
scanf("%s%d",s+1,&k);
for(int i=1;s[i];i++) m+=s[i]=='1';
int t=0;
for(int i=1;s[i];i++)
if(s[i]=='0') a[++n]=t,t=0;
else t++;
a[++n]=t;
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
k=min(k,m);
dp[0][0][0]=1;
for(int i=0;i<n;i++)
for(int j=sum[i];j<=sum[n];j++)
for(int h=0;h<=k;h++)
{
if(!dp[i][j][h]) continue;
for(int f=max(j,sum[i+1]);f<=sum[n];f++)
if(h+f-j-a[i+1]<=k)
{
if(i+1==n&&f-j>a[i+1]) break;
int cost=f-j<=a[i+1]?0:f-j-a[i+1];
dp[i+1][f][h+cost]=(dp[i+1][f][h+cost]+dp[i][j][h])%mod;
}
}
ll ans=0;
for(int i=0;i<=k;i++) ans=(ans+dp[n][m][i])%mod;
printf("%lld\n",ans);
}

171

被折叠的 条评论
为什么被折叠?



