|
這題對我來說太難啦,看了報告半天才弄明白是咋回事。 高手們的解題報告相當飄逸。我來寫一個造福菜鳥的。 首先來看一下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; }
|