#矩阵乘法,线段树#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个矩阵)
}
posted @ 2020-08-11 14:25  lemondinosaur  阅读(125)  评论(0编辑  收藏  举报