题目链接:FZU 1692
题意:每次按a[i]=(a[i]+L*a[(i+1)%n]+R*a[(i-1+n)%n])%M(原题打错了),操作m次后n个数的结果
分析:
矩阵挺好想的:
1 L 0 0 0 0 R a[0]
R 1 L 0 0 0 0 a[1]
0 R 1 L 0 0 0 a[2]
. . . . . . . a[n-1](依次类推)
就是如果直接套快速幂板子会超时.
我们很容易(我没发现 o(≧口≦)o)发现这是个循环矩阵.有矩阵C=AB,如果A和B是循环矩阵则C也是循环矩阵.
- 循环矩阵: 行向量的每个元素都是前一个行向量各元素依次右移一个位置得到的结果。
以下是代码:
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define Fi first
#define Se second
#define ll long long
#define inf 0x3f3f3f3f
#define lowbit(x) (x&-x)
#define PLL pair<ll,ll>
#define PII pair<int,int>
#define l_inf 0x3f3f3f3f3f3f3f
#define mmin(a,b,c) min(a,min(b,c))
#define mmax(a,b,c) max(a,max(b,c))
#define debug(a) cout<<#a<<"="<<a<<endl;
#define Sc_P(x) scanf("%d%d",&x.Fi,&x.Se)
#define Sc_PL(x) scanf("%lld%lld",&x.Fi,&x.Se)
#define debug2(a,b) cout<<#a<<"="<<a<<" "<<#b<<"="<<b<<endl;
using namespace std;
const int N=3e5+10;
const int maxn=105;
ll tmp[maxn][maxn];
ll Mod;
void get_nex(ll a[][maxn],int n)
{
for(int i=2;i<=n;i++)
{
for(int j=2;j<=n;j++)
{
a[i][j]=a[i-1][j-1];
}
a[i][1]=a[i-1][n];
}
}
void multi(ll a[][maxn],ll b[][maxn],int n)//n是矩阵大小
{
int i,j,k;
memset(tmp,0,sizeof tmp);
for(j=1;j<=n;j++)
for(k=1;k<=n;k++)
{
tmp[1][j]+=a[1][k]*b[k][j];
if(tmp[1][j]>=Mod)
tmp[1][j]%=Mod;
}
get_nex(tmp,n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=tmp[i][j];
}
ll res[maxn][maxn];
void Pow(ll a[][maxn],ll m,int n)// a 是初始矩阵 res是答案数组 m是幂,n是矩阵大小
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
res[i][j]=(i==j);
while(m)
{
if(m&1) multi(res,a,n); //res=res*a;
multi(a,a,n); //a=a*a
m>>=1;
}
}
ll a[maxn][maxn],aa[maxn],ans[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll L,R,n,m;
scanf("%lld%lld%lld%lld%lld",&n,&m,&L,&R,&Mod);
for(int i=1;i<=n;i++)
{
scanf("%lld",&aa[i]);
}
memset(a[1],0,sizeof a[1]);
a[1][1]=1;a[1][2]=L%Mod;a[1][n]=R%Mod;
get_nex(a,n);
Pow(a,m,n);
for(int i=1;i<=n;i++)
{
ans[i]=0;
for(int j=1;j<=n;j++)
{
ans[i]+=aa[j]*res[i][j];
if(ans[i]>=Mod)
ans[i]=ans[i]%Mod;
}
}
for(int i=1;i<n;i++)
printf("%lld ",ans[i]);
printf("%lld",ans[n]);
}
return 0;
}
/*
1
3 20000 3 4 1
1002300000 201100045 3010300020
*/
我再吐槽下这题初始化都能搞超时也是无语了