题解:
这道题……看完题就大概知道怎么做,但是考试时没有实现出来。
考试的时候想的是用倍增来实现,但是细节太多写不出来,正解是用线段树来维护连续n个矩阵的乘积,其实这个做法也挺显然的,但是没有把这两个东西放在一起用过。然后细节还是很多,调了一下午。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=50010;
const int inf=2147483647;
LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
struct Node{LL pos,bel;int v;}a[Maxn];
bool cmp(Node a,Node b){return a.pos<b.pos;}
LL K,belK;
int P,n,m,s[Maxn],F[Maxn];
struct Matrix{int v[2][2],r,c;}t,st,one;
Matrix operator * (Matrix a,Matrix b)
{
Matrix c;
memset(c.v,0,sizeof(c.v));
c.r=b.r;c.c=a.c;
for(int i=0;i<=c.r;i++)
for(int j=0;j<=c.c;j++)
for(int k=0;k<=c.r;k++)
c.v[i][j]=(c.v[i][j]+(LL)a.v[k][j]*b.v[i][k]%P)%P;
return c;
}
Matrix Pow(Matrix x,LL y)
{
if(!y)return one;
if(y==1)return x;
Matrix t=Pow(x,y>>1),re=t*t;
if(y&1)re=re*x;
return re;
}
struct Seg{int l,r,lc,rc;Matrix A;}tr[Maxn<<1];
int len=0;
void build(int l,int r)
{
int t=++len;
tr[t].l=l;tr[t].r=r;
if(l==r)
{
tr[t].A.r=tr[t].A.c=1;
tr[t].A.v[0][0]=0,tr[t].A.v[0][1]=1;
tr[t].A.v[1][0]=s[l-1],tr[t].A.v[1][1]=s[l%n];
return;
}
int mid=l+r>>1;
tr[t].lc=len+1,build(l,mid);
tr[t].rc=len+1,build(mid+1,r);
tr[t].A=tr[tr[t].lc].A*tr[tr[t].rc].A;
}
void modify(int x,int p1,int p2,int v)
{
if(tr[x].l==tr[x].r){tr[x].A.v[1][p2]=v;return;}
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
if(p1<=mid)modify(lc,p1,p2,v);
else modify(rc,p1,p2,v);
tr[x].A=tr[lc].A*tr[rc].A;
}
int main()
{
one.r=one.c=1;
one.v[0][0]=one.v[1][1]=1;
one.v[0][1]=one.v[1][0]=0;
K=read(),P=read();
if(K<2)return printf("0"),0;
n=read();
belK=(K-2)/n+1;
for(int i=0;i<n;i++)s[i]=read();
build(1,n);t=tr[1].A;
m=read();
for(int i=1;i<=m;i++)a[i].pos=read(),a[i].v=read(),a[i].bel=(a[i].pos-1)/n+1;
sort(a+1,a+1+m,cmp);
while(a[m].pos>=K&&m)m--;
if(a[m].pos<K-n&&K-n>n)a[++m].pos=K-n,a[m].v=s[(K-n)%n],a[m].bel=(K-n-1)/n+1;
st.r=1,st.c=0;
st.v[0][0]=0,st.v[1][0]=1;
LL now=0;int i=1;
while(i<=m)
{
if((now+1)*n+1>=K)break;
if(now<a[i].bel-1)
{
if(i>1&&a[i-1].pos==now*n)
{
modify(1,1,0,a[i-1].v);
t=tr[1].A;
st=st*t;
modify(1,1,0,s[0]);
t=tr[1].A;
st=st*Pow(t,a[i].bel-2-now),now=a[i].bel-1;
}
else st=st*Pow(t,a[i].bel-1-now),now=a[i].bel-1;
}
if((now+1)*n+1>=K)break;
int j=i;
while(j<=m&&a[j].bel==a[i].bel)j++;j--;
if(i>1&&a[i-1].pos==now*n&&a[i-1].pos%n==0)modify(1,1,0,a[i-1].v);
for(int k=i;k<=j;k++)
{
int tmp=a[k].pos%n;
if(!tmp)modify(1,n,1,a[k].v);
else
{
modify(1,tmp+1,0,a[k].v);
modify(1,tmp,1,a[k].v);
}
}
st=st*tr[1].A;
if(i>1&&a[i-1].pos==now*n&&a[i-1].pos%n==0)modify(1,1,0,s[0]);
for(int k=i;k<=j;k++)
{
int tmp=a[k].pos%n;
if(!tmp)modify(1,n,1,s[0]);
else
{
modify(1,tmp+1,0,s[tmp]);
modify(1,tmp,1,s[tmp]);
}
}
now++;
i=j+1;
}
LL x,tk=K-1;
while((tk-1)%n)tk--;
x=(tk-1)/n;
int t1=-1,t2=-1,cnt=0;
for(int j=1;j<=m;j++)
if(a[j].pos>=(belK-1)*n)
{
if(a[j].pos%n)s[a[j].pos%n]=a[j].v;
else
{
if(a[j].pos==(belK-1)*n)t1=a[j].v;
else t2=a[j].v;
}
}
if(t1==-1)t1=s[0];
if(t2==-1)t2=s[0];
F[0]=st.v[0][0],F[1]=st.v[1][0];
for(LL j=1;j<=K-(belK-1)*n-1;j++)
{
LL s1=s[j%n],s2=s[(j-1)%n];
if(j==1)s2=t1;
if(j==n)s1=t2;
if(j==n+1)s2=t2;
F[j+1]=((LL)F[j]*s1%P+(LL)F[j-1]*s2%P)%P;
}
printf("%d",F[K-(belK-1)*n]);
}