ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF575A Fibonotci

2022-09-11 21:31:46  阅读:166  来源: 互联网

标签:bmatrix int rep tr Fibonotci CF575A define op


题意

给定一个无限的序列 \(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有