FZU 1692 Key problem(构造矩阵+矩阵快速幂)
原创
©著作权归作者所有:来自51CTO博客作者herongwei的原创作品,请联系作者获取转载授权,否则将追究法律责任
【题目链接】点击打开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;
}