看起来就像一个加权的斐波那契数列变形!(这个权是倒序加的,没仔细读题正着构造了矩阵,卡着30分百思不得其解qwq,现在看来应该是k=1的30分)
构造一个矩阵,就可以很方便地求出第n项,但是它要求一段区间和,就在矩阵上加一个前缀和,维护起来非常方便
转移矩阵前n-1列用来继承上次2~n列的状态,第n列用来加权转移第n+1项,第n+1列和第n列转移基本相同,多一个继承前缀和。
#include<iostream> #include<cstring> #include<cstdio> #define int long long using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } int num,n,m,mod; inline int M(int x){ while(x<0ll) x+=mod; return x%mod; } const int MAXN=64; typedef long long ll; struct Mat{ int a[MAXN][MAXN]; Mat(){memset(a,0,sizeof(a));} Mat operator*(const Mat &rhs){ Mat ret; for(int k=1;k<=num+1;k++){ for(int i=1;i<=num+1;i++){ for(int j=1;j<=num+1;j++){ (ret.a[i][j]+=(1ll*a[i][k]*rhs.a[k][j])%mod)%=mod; } } } return ret; } }e; void show(Mat x){ cout<<"=============================== "; for(int i=1;i<=num+1;i++){ for(int j=1;j<=num+1;j++){ cout<<x.a[i][j]<<" "; } cout<<endl; } cout<<"=============================== "; } Mat pow(Mat x,ll y){ Mat ret(e),base(x); while(y){ if(y&1) ret=ret*base; base=base*base; y>>=1ll; } return ret; } int B[MAXN],C[MAXN]; void init(){ for(int i=1;i<=num+1;i++){ e.a[i][i]=1; } } void solve(){ Mat ori; int s=0ll; for(int i=1;i<=num;i++){ ori.a[1][i]=B[i]%mod;s+=B[i];s%=mod; } ori.a[1][num+1]=s; Mat tra; for(int i=1;i<num;i++) tra.a[i+1][i]=1ll; for(int i=1;i<=num;i++) tra.a[i][num]=tra.a[i][num+1]=C[num-i+1];//!! tra.a[num+1][num+1]=1ll; Mat res=pow(tra,n-num); Mat ansn=ori*res,ansm; ll ans=ansn.a[1][num+1]; if(m>num){ res=pow(tra,m-num-1); ansm=ori*res; ans=M(ans-ansm.a[1][num+1]); printf("%lld ",ans); }else{ for(int i=1;i<m;i++) ans=M(ans-B[i]); printf("%lld ",ans); } } signed main(){ num=rd(); for(int i=1;i<=num;i++) B[i]=rd(); for(int i=1;i<=num;i++) C[i]=rd(); m=rd();n=rd();mod=rd(); ll tmp=0; if(n<=num){ for(int i=m;i<=n;i++) (tmp+=B[i])%=mod;// printf("%lld ",tmp); return 0; } init(); solve(); return 0; }