题目链接:https://cn.vjudge.net/problem/UVA-11651
解题思路:
思路来源于网络。
DP + 矩阵快速幂。
设 dp[i][j] 为满足 score 为 i 且最后一位为 j 的数字的个数。则不难推出其状态转移方程:dp[i][j] = Sum( dp[i-d][k] ) { 其中d=(j-k)*(j-k), i!=k }。
因为 score 最高可到 1e9,一是开不出那么大的数组,二是会超时,所以我们需要再加上矩阵快速幂优化。
1、对于一个 dp[i][j],只有 i > score >= max(i - (base-1)2 ,0) 的这一部分有可能对其结果产生影响;
2、这个dp是有周期性,对于score而言,其周期为(base-1)2 {也就是说,假如 dp[i][j] = dp[i-k1][b1] + dp[i-k2][b2] + dp[i-k3][b3],那么对于任意ib = i + k*(base-1)2 (k为任意整数),dp[ib][j] = dp[ib-k1][b1] + dp[ib-k2][b2] + dp[ib-k3][b3]) }。
由于有上述两个性质,故可以用矩阵快速幂优化。
额,感觉讲的不太好。。。在下尽力了。。。下面引用一位大神(http://www.cnblogs.com/AOQNRMGYXLMV/p/5256508.html)的一张图片。。。其实思路也是引用的(逃
当base=3时,有如下转移:(注意,其中倒数第三行有一个错误。至于哪里错了,就留给读者自己发现吧。)
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 4 using namespace std; 5 typedef unsigned int ui; //这里要是不用 unsigned int 的话就会报段错误。 6 const int maxn=150; 7 ui dp[25][6]; 8 struct Matrix { 9 ui mat[maxn][maxn]; 10 }; 11 Matrix Multiply(Matrix x,Matrix y,int n){ 12 Matrix tmp; 13 for(int i=0;i<maxn;i++){ 14 for(int j=0;j<maxn;j++) tmp.mat[i][j]=0; 15 } 16 for(int i=0;i<n;i++){ 17 for(int j=0;j<n;j++){ 18 for(int k=0;k<n;k++){ 19 tmp.mat[i][j]+=x.mat[i][k]*y.mat[k][j]; 20 } 21 } 22 } 23 return tmp; 24 } 25 Matrix Fast_Power(Matrix a,int m,int n){ 26 Matrix res; 27 for(int i=0;i<maxn;i++){ 28 for(int j=0;j<maxn;j++) res.mat[i][j]=0; 29 } 30 for(int i=0;i<n;i++) res.mat[i][i]=1; 31 while(m){ 32 if(m&1) res=Multiply(res,a,n); 33 m>>=1; 34 a=Multiply(a,a,n); 35 } 36 return res; 37 } 38 int main(){ 39 int T,base,sc; 40 Matrix temp,Right; 41 scanf("%d",&T); 42 for(int t=1;t<=T;t++){ 43 scanf("%d%d",&base,&sc); 44 printf("Case %d: ",t); 45 memset(dp,0,sizeof(dp)); 46 memset(Right.mat,0,sizeof(Right.mat)); 47 memset(temp.mat,0,sizeof(temp.mat)); 48 int ind=1; 49 dp[0][0]=0; //注意:dp[0][0] = 0, dp[0][i] = 1 (i>0) 50 Right.mat[0][0]=0; 51 for(int i=1;i<base;i++){ 52 dp[0][i]=1; 53 Right.mat[ind][0]=dp[0][i]; 54 ind++; 55 } 56 57 for(int i=1;i<(base-1)*(base-1);i++){ 58 for(int j=0;j<base;j++){ 59 for(int k=0;k<i;k++){ 60 for(int z=0;z<base;z++){ 61 if(z!=j&&i-k==(z-j)*(z-j)) dp[i][j]+=dp[k][z]; 62 } 63 } 64 Right.mat[ind][0]=dp[i][j]; 65 ind++; 66 } 67 } 68 ui cnt=0; 69 for(int i=0;i+base<(base-1)*(base-1)*base;i++) 70 temp.mat[i][i+base]=1; 71 for(int i=0;i<base;i++){ 72 for(int j=0;j<(base-1)*(base-1);j++){ 73 for(int k=0;k<base;k++){ 74 if(k!=i&&(base-1)*(base-1)-j==(i-k)*(i-k)) temp.mat[base*((base-1)*(base-1)-1)+i][j*base+k]=1; 75 } 76 } 77 } 78 temp=Fast_Power(temp,sc,(base-1)*(base-1)*base); 79 Matrix ans=Multiply(temp,Right,(base-1)*(base-1)*base); 80 for(int i=0;i<base;i++) cnt=cnt+ans.mat[i][0]; 81 printf("%u ",cnt); 82 83 } 84 return 0; 85 }