A Takahashikun, The Strider
往某个方向走1步,那就要在这个方向的对立方向(转180度)往回走1步。那么只要转了是360的倍数,各个方向和其对立方向走的步数是相同的,答案为
L
C
M
(
x
,
360
)
/
x
LCM(x,360)/x
LCM(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
考虑倒退操作,每次可以删除一行或删除一列,然后给删除的这一行或一列染色。但是方案有重复的,我们规定能删列则删列,否则删行,这样方案数唯一。
设
d
p
[
i
]
[
j
]
[
0
/
1
]
dp[i][j][0/1]
dp[i][j][0/1]为
i
i
i行
j
j
j列,
0
0
0表示只能删行,
1
1
1表示行列都可以删。
对于
d
p
[
i
]
[
j
]
[
0
]
dp[i][j][0]
dp[i][j][0]转移到
d
p
[
i
−
1
]
[
j
]
[
1
]
dp[i-1][j][1]
dp[i−1][j][1]的情况,只有第
j
j
j列有两个以上的黑块的时候,才能只删行,如果只有一个黑怪会遵循优先删列的原则不能删行,那么这个转移的系数就是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
−
1
n-1
n−1个字符
0
0
0,那么我们得到了
n
n
n个缝隙,在这
n
n
n个缝隙里放入字符
1
1
1,就得到了所有方案数。
设
d
p
[
i
]
[
j
]
[
h
]
dp[i][j][h]
dp[i][j][h],前
i
i
i个缝隙,共放了
j
j
j个
1
1
1,进行
h
h
h次操作的方案数。
在任意时候,需要满足
j
>
=
s
u
m
[
i
]
j>=sum[i]
j>=sum[i],因为字符
1
1
1不能往后扔,只能往前扔。
然后得到了一个看起来 O ( n 4 ) O(n^4) O(n4)的 d p dp dp,但是系数之间的关系,满足 i + j = ∣ S ∣ , h < = m i n ( k , i ) i+j=|S|,h<=min(k,i) i+j=∣S∣,h<=min(k,i),这样我们期望实际的 i , j , h i,j,h i,j,h为 300 / 2 = 150 300/2=150 300/2=150。又由于 j > = s u m [ i ] j>=sum[i] j>=sum[i]的约束,有很多无用的状态,又由于常数非常小,我们期望的时间复杂度变成了 O ( n 3 ) 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);
}