ARC162F
%赛场切了!
矩阵是不太好处理的,所以考虑从一行去推下一行。
设上一行选择了
(下列结合自己画图理解)
。
首先发现如果选择一个
然后也可以发现,设这一行的选择的
但是又发现,如果有一行完全不选,则这一行状态可以视为继承上一行的。这个要特判一下。
。
结合前面,发现可以任选。
于是我们可以开始 dp 了。
设
首先转移
然后在上一步的基础上转移
于是能写出如下
点击查看代码
fac[0]=1;
rep(i,1,m)fac[i]=1ll*fac[i-1]*i%mod;
ifac[m]=qpow(fac[m],mod-2);
drep(i,m-1,0)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
rep(i,1,m)rep(j,0,m)dp[1][i][j]=binom(m-j-1,i-1);
dp[1][0][m]=1;
rep(i,2,n){
mems(f,0);
rep(j,0,m){
rep(k,0,m){
rep(l,0,j)dp[i][l][k]=Mod(dp[i][l][k],dp[i-1][j][k]);
if(j)f[j][k]=Mod(f[j][k],dp[i-1][j][k]),f[0][k]=Mod(f[0][k],mod-dp[i-1][j][k]);
}
}
rep(j,0,m){
rep(k,0,m){
rep(l,1,k)rep(p,0,k-l)f[j+p+1][l-1]=Mod(f[j+p+1][l-1],1ll*dp[i][j][k]*binom(k-l,p)%mod);
}
}
rep(j,0,m)rep(k,0,m)dp[i][j][k]=Mod(dp[i][j][k],f[j][k]);
}
int ans=0;
rep(i,0,m)rep(j,0,m)ans=Mod(ans,dp[n][i][j]);
printf("%d\n",ans);
然后开始优化!
发现我们的状态已经足够优秀了。从转移入手。
瓶颈在
点击查看代码
rep(i,2,n){
mems(f,0),mems(g,0);
rep(j,0,m){
rep(k,0,m){
rep(l,0,j)f[l][k]=Mod(f[l][k],dp[i-1][j][k]);
if(j)dp[i][j][k]=Mod(dp[i][j][k],dp[i-1][j][k]),dp[i][0][k]=Mod(dp[i][0][k],mod-dp[i-1][j][k]);
}
}
rep(j,0,m){
drep(k,m,0){
rep(l,1,k)f[j+1][l-1]=Mod(f[j+1][l-1],f[j][k]);
}
}
rep(j,0,m)rep(k,0,m)dp[i][j][k]=Mod(dp[i][j][k],f[j][k]);
}
然后继续优化!
发现上面的
于是变成了
点击查看代码
rep(i,2,n){
mems(f,0);
rep(k,0,m){
s[0]=dp[i-1][0][k];
rep(j,1,m)s[j]=Mod(s[j-1],dp[i-1][j][k]);
rep(l,0,m)f[l][k]=Mod(f[l][k],Mod(s[m],mod-s[l-1]));
}
rep(j,0,m){
rep(k,0,m){
if(j)dp[i][j][k]=Mod(dp[i][j][k],dp[i-1][j][k]),dp[i][0][k]=Mod(dp[i][0][k],mod-dp[i-1][j][k]);
}
}
rep(j,0,m){
s[0]=0;
rep(k,1,m)s[k]=Mod(s[k-1],f[j][k]);
drep(l,m,1){
f[j+1][l-1]=Mod(f[j+1][l-1],Mod(s[m],mod-s[l-1]));
}
}
rep(j,0,m)rep(k,0,m)dp[i][j][k]=Mod(dp[i][j][k],f[j][k]);
}
然后可能被卡空间,使滚动,空间
code:
int n,m,dp[2][N][N],f[N][N],s[N];
il int Mod(int x,int y){return x+y>=mod?x+y-mod:x+y;}
void solve3(){
dp[0][0][m]=1;
rep(i,1,n){
int p=i&1;
mems(f,0),mems(dp[p],0);
rep(k,0,m){
s[0]=dp[p^1][0][k];
rep(j,1,m)s[j]=Mod(s[j-1],dp[p^1][j][k]);
rep(l,0,m)f[l][k]=Mod(f[l][k],Mod(s[m],mod-s[l-1]));
}
rep(j,0,m){
rep(k,0,m){
if(j)dp[p][j][k]=Mod(dp[p][j][k],dp[p^1][j][k]),dp[p][0][k]=Mod(dp[p][0][k],mod-dp[p^1][j][k]);
}
}
rep(j,0,m){
s[0]=0;
rep(k,1,m)s[k]=Mod(s[k-1],f[j][k]);
drep(l,m,1)f[j+1][l-1]=Mod(f[j+1][l-1],Mod(s[m],mod-s[l-1]));
}
rep(j,0,m)rep(k,0,m)dp[p][j][k]=Mod(dp[p][j][k],f[j][k]);
}
int ans=0;
rep(i,0,m)rep(j,0,m)ans=Mod(ans,dp[n&1][i][j]);
printf("%d\n",ans);
}
void Yorushika(){
scanf("%d%d",&n,&m);
solve3();
}
signed main(){
int t=1;
// scanf("%d",&t);
while(t--)
Yorushika();
}
横向对比,发现这个方法不需要组合数,所以事实上是可以做任意模数的!😃