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;
}

浙公网安备 33010602011771号