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;
}

  

posted @ 2017-06-30 04:06  Claris  阅读(212)  评论(0编辑  收藏  举报