|
这题对我来说太难啦,看了报告半天才弄明白是咋回事。 高手们的解题报告相当飘逸。我来写一个造福菜鸟的。 首先来看一下Sample里的第一组数据。 1 2 2 1 2 经过一次变换之后就成了 5 5 5 5 4 它的原理就是 a0 a1 a2 a3 a4 -> (a4+a0+a1) (a0+a1+a2) (a1+a2+a3) (a2+a3+a4) (a3+a4+a0) 如果用矩阵相乘来描述,那就可以表述为1xN和NxN的矩阵相乘,结果仍为1xN矩阵 a = 1 2 2 1 2 b = 1 1 0 0 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 1 1 a * b = 5 5 5 5 4 所以最终结果就是:a * (b^k) 线性代数不合格的同鞋表示压力很大。。 对一个NxN矩阵求k次方,而且这个k很大,N也不小,怎么办? 所以有高手观察到了,这个矩阵长得有点特殊,可以找到一些规律: b^1 = [1, 1, 0, 0, 1] [1, 1, 1, 0, 0] [0, 1, 1, 1, 0] [0, 0, 1, 1, 1] [1, 0, 0, 1, 1] b^2 = [3, 2, 1, 1, 2] [2, 3, 2, 1, 1] [1, 2, 3, 2, 1] [1, 1, 2, 3, 2] [2, 1, 1, 2, 3] b^3 = [7, 6, 4, 4, 6] [6, 7, 6, 4, 4] [4, 6, 7, 6, 4] [4, 4, 6, 7, 6] [6, 4, 4, 6, 7] b^4 = [19, 17, 14, 14, 17] [17, 19, 17, 14, 14] [14, 17, 19, 17, 14] [14, 14, 17, 19, 17] [17, 14, 14, 17, 19] 发现神马没有。就是无论是b的几次幂,都符合A[i][j] = A[i-1][j-1]
高手说是这样推倒出来地: ““”
利用矩阵A,B具有a[i][j]=A[i-1][j-1],B[i][j]=B[i-1][j-1](i-1<0则表示i-1+n,j-1<0则表示j-1+n)
我们可以得出矩阵C=a*b也具有这个性质
C[i][j]=sum(A[i][t]*B[t][j])=sum(A[i-1][t-1],B[t-1][j-1])=sum(A[i-1][t],B[t][j-1])=C[i-1][j-1]
“”“ 这样就可以开一个N大小的数组来存放每次计算的结果了。而没必要用NxN。 N的问题解决了,但是k还是很大,怎么办? 这时候可以用二分法来求b^k b^k = b^1 * b^4 * b^16 。。。 计算过程中,必定会出现数字大于M的情况。 切记 x*y = (x%M)*(y%M) 最后,经过多次优化,这题的代码居然被高手写成了如下的一小坨,实在是。。给力哇
#include<iostream> using namespace std; int n,m,d,k; void mul(long long a[],long long b[]) { int i,j; long long c[501]; for(i=0;i<n;++i)for(c[i]=j=0;j<n;++j)c[i]+=a[j]*b[i>=j?(i-j):(n+i-j)]; for(i=0;i<n;b[i]=c[i++]%m); } long long init[501],tmp[501]; int main() { int i,j; scanf("%d%d%d%d",&n,&m,&d,&k); for(i=0;i<n;++i)scanf("%I64d",&init[i]); for(tmp[0]=i=1;i<=d;++i)tmp[i]=tmp[n-i]=1; while(k) { if(k&1)mul(tmp,init); mul(tmp,tmp); k>>=1; } for(i=0;i<n;++i)if(i)printf(" %I64d",init[i]);else printf("%I64d",init[i]); printf("\n"); return 0; }
|