【题目链接】点击打开FZU 1692
【题意】:1 题目的意思是有n个人构成一个圈,每个人初始的有ai个苹果,现在做m次的游戏,每一次游戏过后第i个人能够增加R*A(i+n-1)%n+L*A(i+1)%n 个苹果(题目有错),问m轮游戏过后每个人的苹果数
【思路】:
根据题目的意思我们能够列出一轮过后每个人的苹果数
a0 = a0+R*an-1+L*a1
a1 = a1+R*a0+L*a2
.............................
an-1 = an-1+R*an-2+L*a0
3 根据第二条思路我们可以构造出如下的矩阵
1 L 0 ...... R a0 a0'
R 1 L ......... * a1 a1'
................... .... = ......
...........R 1 L an-2 an-2'
L ...........R 1 an-1 an-1'
4 那么根据3我们可以利用矩阵快速幂求出最后的答案,但是题目的n最大为100,m最大为10^9,那么每个case的时间复杂度为O(Logm*n^3),当n最大为100的时候是会TLE的
5 我们发现初始的矩阵里面,矩阵是一个循环同构的,就是说矩阵的每一行度能够从上一行推出,那么我们只要利用O(n^2)的时间求出第一行,然后我们在利用递推求出剩下的n-1行,那么总的时间复杂度为O(Logm*n^2)
代码:
/* Problem id. FZU 1692 RunID: 631373 UserID: ACM_herongwei Submit time: 2015-09-04 11:58:16 Language: C++ Length: 1806 Bytes. Result: Accepted */ #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int N=105; int arr[N]; int n,m,L,R,MOD; struct mut { LL mat[N][N]; mut() { memset(mat,0,sizeof(mat)); } void init() { for(int i=0; i<n; ++i) { mat[i][(i+n-1)%n]=L; mat[i][i]=1; mat[i][(i+1)%n]=R; } } }; mut multi(mut &a,mut &b) { mut c; for(int i=0; i<n; ++i) { if(a.mat[0][i]) { for(int j=0; j<n; ++j) { if(b.mat[i][j]) { c.mat[0][j]=(c.mat[0][j]+a.mat[0][i]*b.mat[i][j])%MOD; } } } } for(int i = 1; i < n; i ++) { c.mat[i][0] = c.mat[i - 1][n - 1]; for(int j = 1; j <n; j ++) c.mat[i][j] = c.mat[i - 1][j - 1]; } return c; } mut poww(mut unit, mut a,int n) { while(n) { if(n&1) unit=multi(unit,a); a=multi(a,a); n>>=1; } return unit; } void solve() { int ans=0; mut unit,a; scanf("%d %d %d %d %d",&n,&m,&R,&L,&MOD); for(int i=0; i<n; ++i) { scanf("%d",&arr[i]); unit.mat[i][i]=1; } a.init(); unit=poww(unit,a,m); for(int i=0; i<n; ++i) { ans=0; for(int j=0; j<n; ++j) { if(unit.mat[i][j]&&arr[j]) ans+=(unit.mat[i][j]*arr[j])%MOD; } if(i) printf(" "); printf("%d",ans%MOD); } puts(""); } int main() { int t; scanf("%d",&t); while(t--) { solve(); } return 0; }