CF575A Fibonotci

Fibonotci

线段树维护矩阵。

题意

给定下标从 \(0\) 开始的周期为 \(n\) 的数组,并修改其中 \(m\) 个位置的值。

我们定义数列 \(f\),满足 \(f_0=0\)\(f_1=1\)\(f_i=s_{i-2} \times f_{i-2} + s_{i-1} \times f_{i-1}\)

所有修改结束后,求 \(f_k \bmod p\) 的值。

\(1 \leq n,m \leq 5 \times 10^4\)\(1 \leq k \leq 10^{18}\)\(1 \leq p \leq 10^9\)

思路

看到斐波那契数列想到矩阵维护。

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

所以你发现修改 \(m\) 个位置的值等价于修改 \(O(m)\) 个转移矩阵。

此时会构成 \(O(m)\) 个连续的周期规则段,是可以通过线段树求出的。

\[\begin{bmatrix} f_{n-1} & f_n \end{bmatrix} = \begin{bmatrix} 0 & 1 \end{bmatrix} \times \prod_{i=0}^{n-2} \begin{bmatrix} 0 & s_{i}\\ 1 & s_{i+1} \end{bmatrix} \]

代码

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
long long s[50000],mod;
int n;
struct Matrix{
	long long matrix[2][2];
}I=(Matrix){{{1,0},{0,1}}};
const Matrix operator *(const Matrix &x,const Matrix &y);
const Matrix operator ^(const Matrix &x,const long long &y);
struct Node{
	int l,r;
	Matrix tr;
}a[400010];
void pushup(int id){
	a[id].tr=a[id*2].tr*a[id*2+1].tr;
}
void build(int id,int l,int r){
	a[id].l=l;
	a[id].r=r;
	if(a[id].l==a[id].r){
		a[id].tr=(Matrix){{{0,s[l%n]},{1,s[(l+1)%n]}}};
	}
	else{
		int mid=(l+r)>>1;
		build(id*2,l,mid);
		build(id*2+1,mid+1,r);
		pushup(id);
	}
}
Matrix query(int id,int l,int r){
	if(l<=a[id].l  &&  a[id].r<=r){
		return a[id].tr;
	}
	Matrix ans=I;
	if(l<=a[id*2].r){
		ans=ans*query(id*2,l,r);
	}
	if(a[id*2+1].l<=r){
		ans=ans*query(id*2+1,l,r);
	}
	return ans;
}
map<long long,Matrix> modify;
void init(long long pos){
	if(modify.find(pos)==modify.end()){
		modify[pos]=(Matrix){{{0,s[pos%n]},{1,s[(pos+1)%n]}}};
	}
}
struct Modify{
	long long pos;
	Matrix tr; 
}modi[100010];
Matrix trans(long long l,long long r){
	if(l/n==r/n){
		return query(1,l%n,r%n);
	}
	Matrix ans=I;
	ans=ans*query(1,l%n,n-1);
	ans=ans*(query(1,0,n-1)^(r/n-l/n-1));
	ans=ans*query(1,0,r%n);
	return ans;
}
int main(){
	long long k;
	scanf("%lld %lld",&k,&mod);
	if(mod==1){
		printf("0");
		return 0;
	}
	if(k<2){
		printf("%lld",k);
		return 0;
	}
	k-=2;
	scanf("%d",&n); 
	for(int i=0;i<n;i++){
		scanf("%lld",&s[i]);
		s[i]%=mod;
	}
	int m;
	scanf("%d",&m);
	while(m--){
		long long pos,num;
		scanf("%lld %lld",&pos,&num);
		if(pos-1<=k){
			init(pos-1);
			modify[pos-1].matrix[1][1]=num;
		}
		if(pos<=k){
			init(pos);
			modify[pos].matrix[0][1]=num;
		}
	}
	int tot=0;
	modi[++tot]=(Modify){-1,I};
	for(map<long long,Matrix> :: iterator i=modify.begin();i!=modify.end();i++){
		modi[++tot]=(Modify){i->first,i->second};
	}
	modi[++tot]=(Modify){k+1,I};
	Matrix ans=I;
	build(1,0,n-1);
	for(int i=1;i<tot;i++){
		if(modi[i].pos+1<=modi[i+1].pos-1){
			ans=ans*trans(modi[i].pos+1,modi[i+1].pos-1);
		}
		ans=ans*modi[i+1].tr;
	}
	printf("%lld",ans.matrix[1][1]);
	return 0;
}
const Matrix operator *(const Matrix &x,const Matrix &y){
	Matrix z;
	for(int i=0;i<2;i++){
		for(int j=0;j<2;j++){
			z.matrix[i][j]=0;
			for(int k=0;k<2;k++){
				z.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j]%mod;
				z.matrix[i][j]%=mod;
			}
		}
	}
	return z;
}
const Matrix operator ^(const Matrix &x,const long long &y){
	if(y==0) return I;
	Matrix ans=x^(y/2);
	ans=ans*ans;
	if(y%2==1) ans=ans*x;
	return ans;
}
posted @ 2025-05-20 13:25  Oken喵~  阅读(1)  评论(0)    收藏  举报