BZOJ3655 : 神经错乱数
注意到前3个操作都不会影响每列的情况,而第4个操作必然会将行列交换,故只要每行的和相同即可满足条件。
考虑数位DP,设$f[i][j][k][t]$表示考虑最高的$i$位,第一行的和是$j$,当前行的和是$k$,与$R$的大小关系为$t$的数字个数。
需要特判$|R|=1$以及$|R|$不是完全平方数的情况。
#include<cstdio> int n,m,s,a[20],i,j,k,x,t,nx;long long R,f[20][40][40][2],ans; int main(){ scanf("%lld",&R); if(R<10)return printf("%lld",R+1),0; while(R)a[n++]=R%10,R/=10; if(n!=4&&n!=9&&n!=16)return puts("0"),0; for(m=1;m*m<n;m++); s=m*9; for(i=1;i<=a[n-1];i++)f[n-1][0][i][i==a[n-1]]++; for(i=n-1;i;i--)for(j=0;j<=s;j++)for(k=0;k<=s;k++)for(x=0;x<2;x++)if(f[i][j][k][x]) for(t=0;t<10;t++){ if(x&&t>a[i-1])continue; nx=x&&t==a[i-1]; if(i%m)f[i-1][j][k+t][nx]+=f[i][j][k][x]; else if(i/m==(n-1)/m)f[i-1][k][t][nx]+=f[i][j][k][x]; else if(j==k)f[i-1][j][t][nx]+=f[i][j][k][x]; } for(j=0;j<=s;j++)for(x=0;x<2;x++)ans+=f[0][j][j][x]; return printf("%lld",ans),0; }