其他分享
首页 > 其他分享> > CF575A Fibonotci

CF575A Fibonotci

作者:互联网

题意

给定一个无限的序列 \(s\),周期为 \(n\),并给定 \(s_{0\sim n-1}\)。在给定 \(m\) 个位置修改 \(s\) 的值。

对于一个 \(f\),有 \(f_i=s_{i-1}f_{i-1}+s_{i-2}f_{i-2}\),求 \(f_k\mod p\)。

Solution

由于 \(k\) 比较大,所以一眼考虑快速幂。很快可以推出转移矩阵:

\[\begin{bmatrix} f_{i}\\f_{i-1} \end{bmatrix}= \begin{bmatrix} s_{i-1}&s_{i-2}\\ 1&0 \end{bmatrix} \begin{bmatrix} f_{i-1}\\f_{i-2} \end{bmatrix} \]

很容易想到先把一段周期的矩阵乘起来再快速幂。

然后考虑有 \(m\) 个位置需要修改,所以对 \(n\) 个位置建一棵线段树,每次特殊处理这些被修改过的区间即可。

感觉细节挺多的。首先是如果这个修改在边界处,则两段都要改。所以较好的实现姿势是把一次修改拆成修改两个矩阵。

完蛋了,我 tm 学的左乘,导致我所有的乘法运算都要倒过来做,所幸这题并不是十分麻烦。

Code

#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<' '<<a<<' '
#define pts(a) cerr<<#a<<' '<<a<<'\n'
#define int long long
using namespace std;
const int MAXN=5e4+10;
const int SIZ=2;
int MOD;
struct Mat{
	int a[SIZ][SIZ];
	Mat(){}
	Mat(int s1,int s2){
		a[0][0]=s1;a[0][1]=s2;
		a[1][0]=1;a[1][1]=0;
	}
	Mat friend operator*(Mat m1,Mat m2){
		Mat ret;memset(ret.a,0,sizeof(ret.a));
		rep(i,0,SIZ-1) rep(k,0,SIZ-1) if(m1.a[i][k])
		rep(j,0,SIZ-1) (ret.a[i][j]+=m1.a[i][k]*m2.a[k][j]%MOD)%=MOD;
		return ret;
	}
	void print(){
		cerr<<a[0][0]<<' '<<a[0][1]<<'\n';
		cerr<<a[1][0]<<' '<<a[1][1]<<'\n';
		cerr<<"------------\n";
	}
};
Mat ksm(Mat m,int p){
	Mat ret;memset(ret.a,0,sizeof(ret.a));
	ret.a[0][0]=ret.a[1][1]=1;
	while(p){
		if(p&1) ret=ret*m;
		m=m*m; p>>=1;
	}return ret;
}
struct Tree{int l,r;Mat info;}tr[MAXN<<2];
#define ls i<<1
#define rs i<<1|1
int s[MAXN],n;
void pushup(int i){
	tr[i].info=tr[rs].info*tr[ls].info;
}
void build(int i,int l,int r){
	tr[i].l=l;tr[i].r=r;
	if(l==r){tr[i].info=Mat(s[l%n],s[(l-1)%n]);return;}
	int mid=(l+r)>>1;build(ls,l,mid);build(rs,mid+1,r);
	pushup(i);
}
void upd(int i,int x,Mat v){
	if(tr[i].l==tr[i].r){tr[i].info=v;return;}
	int mid=(tr[i].l+tr[i].r)>>1;
	if(x<=mid) upd(ls,x,v);else upd(rs,x,v);
	pushup(i);
}
Mat ask(int i,int l,int r){
	if(tr[i].l==l&&tr[i].r==r) return tr[i].info;
	int mid=(tr[i].l+tr[i].r)>>1;
	if(r<=mid) return ask(ls,l,r);else if(l>mid) return ask(rs,l,r);
	else return ask(rs,mid+1,r)*ask(ls,l,mid);
}
struct upds{
	int j,v;
	void input(){cin>>j>>v;}
	bool friend operator<(upds a,upds b){return a.j<b.j;}
}u[MAXN];
struct Upds{
	int j;Mat v;
}U[MAXN<<1];
int bl(int id){
	return (id-1)/n+1;
}
void solve(){
	int k;cin>>k>>MOD;
	cin>>n;
	rep(i,0,n-1) cin>>s[i];
	build(1,1,n);
	Mat op;memset(op.a,0,sizeof(op.a));
	op.a[0][0]=op.a[1][1]=1;
	int m;cin>>m;
	rep(i,1,m) u[i].input();
	if(k==0){
		cout<<0%MOD<<'\n';
		return;
	}else if(k==1){
		cout<<1%MOD<<'\n';
		return;
	}k--;
	sort(u+1,u+1+m);
	int mm=0;
	rep(i,1,m){
		U[++mm].j=u[i].j;
		if(u[i-1].j+1==u[i].j) U[mm].v=Mat(u[i].v,u[i-1].v);
		else U[mm].v=Mat(u[i].v,s[(u[i].j-1)%n]);
		U[++mm].j=u[i].j+1;
		if(u[i].j+1==u[i+1].j) U[mm].v=Mat(u[i+1].v,u[i].v);
		else U[mm].v=Mat(s[(u[i].j+1)%n],u[i].v);
	}
	int lst=0,st=-1,ed=-1;
	for(int l=1,r;l<=mm;l=r+1){
		r=l;while(r+1<=mm&&bl(U[r+1].j)==bl(U[l].j)) r++;
		if(bl(U[l].j)==bl(k)){st=l;ed=r;break;}
		else if(bl(U[l].j)>bl(k)) break;
		op=ksm(tr[1].info,bl(U[l].j)-lst-1)*op;
		rep(i,l,r) upd(1,(U[i].j-1)%n+1,U[i].v);
		op=tr[1].info*op;lst=bl(U[l].j);
		rep(i,l,r) upd(1,(U[i].j-1)%n+1,Mat(s[U[i].j%n],s[(U[i].j-1)%n]));
	}
	op=ksm(tr[1].info,bl(k)-lst-1)*op;
	if(ed!=-1)
		rep(i,st,ed) upd(1,(U[i].j-1)%n+1,U[i].v);
	op=ask(1,1,(k-1)%n+1)*op;
	Mat ans;memset(ans.a,0,sizeof(ans.a));
	ans.a[0][0]=1;
	ans=op*ans;
	cout<<ans.a[0][0]<<'\n';
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//	int T;for(cin>>T;T--;)
		solve();
	return 0;
}

标签:bmatrix,int,rep,tr,Fibonotci,CF575A,define,op
来源: https://www.cnblogs.com/ZCETHAN/p/16684880.html