#矩阵乘法,线段树#CF575A Fibonotci
分析
\(K\)那么大肯定是矩阵乘法,
带修改可以用线段树单点修改,
转移矩阵类似于斐波那契数列,
这题思维难度不大,细节很多,需要很长时间QWQ
时间复杂度\(O(mlog_2K)\),具体注释在代码中
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=50011; typedef long long lll;
struct rec{lll x; int y,type;}q[N<<1];
struct maix{int p[2][2];}A[N],B[N],ANS,w[N<<2],W[61];
int mod,a[N],n,m; lll pos;
inline lll iut(){
rr lll ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline maix mul(maix A,maix B,int t=2){
rr maix C;
for (rr int i=0;i<t;++i) for (rr int j=0;j<2;++j)
C.p[i][j]=mo(1ll*A.p[i][0]*B.p[0][j]%mod,1ll*A.p[i][1]*B.p[1][j]%mod);
return C;
}
inline void build(int k,int l,int r){
if (l==r){
w[k]=A[l];
return;
}
rr int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
w[k]=mul(w[k<<1],w[k<<1|1]);
}
inline void update(int k,int l,int r,int x){
if (l==r){
w[k]=B[x];
return;
}
rr int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x);
else update(k<<1|1,mid+1,r,x);
w[k]=mul(w[k<<1],w[k<<1|1]);
}
bool cmp(rec x,rec y){return x.x<y.x;}
inline maix doit(lll x){
rr maix ANS;
ANS.p[0][0]=1,ANS.p[1][0]=0,
ANS.p[0][1]=0,ANS.p[1][1]=1;
for (rr int i=0;i<60;++i)
if ((x>>i)&1) ANS=mul(ANS,W[i]);
return ANS;
}
signed main(){
pos=iut(),mod=iut(),n=iut(),ANS.p[0][1]=1;
for (rr int i=0;i<n;++i) a[i]=iut()%mod;
for (rr int i=1;i<=n;++i) A[i].p[1][1]=a[i%n],A[i].p[0][1]=a[i-1],A[i].p[1][0]=1,B[i]=A[i];
m=iut();
for (rr int i=1;i<=m;++i) q[i+m].x=(q[i].x=iut())+1,q[i+m].y=q[i].y=iut()%mod,q[i].type=1;//一个特例影响两个矩阵
build(1,1,n),sort(q+1,q+1+m*2,cmp),W[0]=w[1];
for (m<<=1;m&&q[m].x>pos;--m); rr lll now,NOW=0;
for (rr int i=1;i<60;++i) W[i]=mul(W[i-1],W[i-1]);
for (rr int l=1,r;l<=m;l=r+1){
for (now=(q[r=l].x-1)/n;r<m&&now==(q[r+1].x-1)/n;++r);//同一个周期
ANS=mul(ANS,doit(now-NOW),1),NOW=now;//中间段快速幂跳过
for (rr int i=l;i<=r;++i){
rr int POS=(q[i].x-1)%n+1;
B[POS].p[q[i].type][1]=q[i].y;
update(1,1,n,POS);
}
if (now==pos/n) break; ANS=mul(ANS,w[1],1),++NOW;
for (rr int i=l;i<=r;++i){
rr int POS=(q[i].x-1)%n+1;
B[POS]=A[POS],update(1,1,n,POS);//恢复原样
}
}
now=pos/n,ANS=mul(ANS,doit(now-NOW),1);
for (rr int i=1;i<=pos%n;++i) ANS=mul(ANS,B[i],1);//散的矩阵单独乘
return !printf("%d",ANS.p[0][0]);//输出前一个(一开始[0,1]代表的是第0个矩阵)
}