正题
题目大意
给出nnn和si(i∈[0..n−1])s_i(i\in[0..n-1])si(i∈[0..n−1]),对于大部分情况有sx=sx%ns_x=s_{x\%n}sx=sx%n。
有递推式Fi=Fi−1si−1+Fi−2si−2F_i=F_{i-1}s_{i-1}+F_{i-2}s_{i-2}Fi=Fi−1si−1+Fi−2si−2
有mmm个情况的sx!=sx%ns_x!=s_{x\% n}sx!=sx%n给出这些情况的sxs_xsx的值
求FKF_KFK
解题思路
考虑没有mmm的情况,每个长度为nnn的快的转移相同,我们可以用矩阵乘法快速幂计算。
那么我们可以在有修改的间隔之中可以用矩阵乘法快速幂算,然后对于中间修改的点,我们可以用线段树维护区间的矩阵乘法积进行单点修改即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=5e5+10;
struct matrix{ll a[2][2];
}w[N*4],ans,f,pre[N],r[N];
struct node{ll x,y,f;
}q[N];
ll n,m,K,P,s[N];
matrix operator*(matrix a,matrix b){matrix c;memset(c.a,0,sizeof(c.a));for(ll i=0;i<2;i++)for(ll j=0;j<2;j++)for(ll k=0;k<2;k++)(c.a[i][j]+=b.a[i][k]*a.a[k][j]%P)%=P;return c;
}
void Build(ll x,ll L,ll R){if(L==R){w[x].a[0][1]=1;w[x].a[1][0]=s[L-1];w[x].a[1][1]=s[L];pre[L]=r[L]=w[x];return;}ll mid=(L+R)>>1;Build(x*2,L,mid);Build(x*2+1,mid+1,R);w[x]=w[x*2]*w[x*2+1];return;
}
void Change(ll x,ll L,ll R,ll pos,matrix val){if(L==R){w[x]=val;return;}ll mid=(L+R)>>1;if(pos<=mid)Change(x*2,L,mid,pos,val);if(pos>mid)Change(x*2+1,mid+1,R,pos,val);w[x]=w[x*2]*w[x*2+1];return;
}
matrix Ask(ll x,ll L,ll R,ll l,ll r){if(L==l&&R==r)return w[x];ll mid=(L+R)>>1;if(r<=mid)return Ask(x*2,L,mid,l,r);if(l>mid)return Ask(x*2+1,mid+1,R,l,r);return Ask(x*2,L,mid,l,mid)*Ask(x*2+1,mid+1,R,mid+1,r);
}
bool cmp(node x,node y)
{return x.x<y.x;}
matrix power(ll b){matrix ans,x=f;ans.a[0][0]=1;ans.a[0][1]=0;ans.a[1][0]=0;ans.a[1][1]=1;while(b){if(b&1)ans=ans*x;x=x*x;b>>=1;} return ans;
}
int main()
{scanf("%lld%lld",&K,&P);scanf("%lld",&n);for(ll i=0;i<n;i++)scanf("%lld",&s[i]);s[n]=s[0]; Build(1,1,n);f=w[1];ll M;scanf("%lld",&M);for(ll i=1;i<=M;i++){ll x,y;scanf("%lld%lld",&x,&y);q[++m].x=x;q[m].y=y;q[m].f=1;q[++m].x=x+1;q[m].y=y;q[m].f=0;}sort(q+1,q+1+m,cmp);ans.a[0][0]=ans.a[1][1]=1;ll zz=0;for(ll i=1,j;i<=m;i=j+1){j=i;ll c=(q[i].x-1)/n;while(j<m&&(q[j+1].x-1)/n<=c)j++;for(ll k=i;k<=j;k++){ll pos=(q[k].x-1)%n+1;r[pos].a[1][q[k].f]=q[k].y;Change(1,1,n,pos,r[pos]);}if(c==K/n)break;ans=ans*power(c-zz);ans=ans*w[1];zz=c+1;for(ll k=i;k<=j;k++){ll pos=(q[k].x-1)%n+1; r[pos]=pre[pos];Change(1,1,n,pos,r[pos]);}}ans=ans*power(K/n-zz);for(ll i=1;i<=K%n;i++)ans=ans*r[i];printf("%lld",ans.a[0][1]);return 0;
}