这是个线性递推,可以用
2
∗
2
2*2
2∗2的矩乘转移,没有特殊位置的话可以直接快速幂。
现在有特殊数字,这也不难。考虑按特殊位置分段,段内直接转移,特殊位置再特殊乘一下。有个比较麻烦的情况是两个特殊位置可能距离
<
n
<n
<n,这种情况下我们可以拿个线段树查询一下区间矩阵乘积。
时间复杂度
O
(
(
n
+
m
)
(
log
n
+
log
V
)
)
\mathcal O((n+m)(\log n+\log V))
O((n+m)(logn+logV))。
#include <bits/stdc++.h>
#define last last2
using namespace std;
typedef long long ll;
int MOD;
struct Matrix {
int num[2][2],n,m;
Matrix() {}
Matrix(int a,int b):n(a),m(b) {memset(num,0,sizeof(num));}
};
Matrix operator * (Matrix a,Matrix b) {
Matrix c(a.n,b.m);
for(int i=0;i<c.n;i++)
for(int j=0;j<c.m;j++)
for(int k=0;k<a.m;k++) c.num[i][j]=(c.num[i][j]+(ll)a.num[i][k]*b.num[k][j])%MOD;
return c;
}
Matrix operator ^ (Matrix a,ll k) {
Matrix ans(a.n,a.m);
for(int i=0;i<ans.n;i++) ans.num[i][i]=1;
while (k) {
if (k&1) ans=ans*a;
a=a*a;
k>>=1;
}
return ans;
}
Matrix fir[50005];
namespace SGT {
Matrix mulv[200000];
void build(int l,int r,int o) {
if (l==r) mulv[o]=fir[l];
else {
int m=((l+r)>>1);
build(l,m,o*2);
build(m+1,r,o*2+1);
mulv[o]=mulv[o*2+1]*mulv[o*2];
}
}
Matrix query(int l,int r,int o,int lx,int rx) {
if (l>=lx&&r<=rx) return mulv[o];
else {
int m=((l+r)>>1);
if (m>=rx) return query(l,m,o*2,lx,rx);
if (m<lx) return query(m+1,r,o*2+1,lx,rx);
return query(m+1,r,o*2+1,lx,rx)*query(l,m,o*2,lx,rx);
}
}
}
map <ll,int> mp;
ll val[200005];
int num[200005];
Matrix rmul[50005],lmul[50005];
int main() {
ll k;
scanf("%lld%d",&k,&MOD);
if (!k) {
puts("0");
return 0;
}
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&num[i]);
for(int i=1;i<=n;i++) {
fir[i]=Matrix(2,2);
fir[i].num[0][0]=num[(i-1)%n]%MOD;
fir[i].num[0][1]=num[((i-2)%n+n)%n]%MOD;
fir[i].num[1][0]=1%MOD;
}
lmul[0]=Matrix(2,2);
lmul[0].num[0][0]=lmul[0].num[1][1]=1;
for(int i=1;i<=n;i++) lmul[i]=fir[i]*lmul[i-1];
rmul[n+1]=Matrix(2,2);
rmul[n+1].num[0][0]=rmul[n+1].num[1][1]=1;
for(int i=n;i>0;i--) rmul[i]=rmul[i+1]*fir[i];
SGT::build(1,n,1);
Matrix all=SGT::mulv[1];
int m;
scanf("%d",&m);
int cnt=0;
for(int i=1;i<=m;i++) {
ll x;
int y;
scanf("%lld%d",&x,&y);
mp[x]=y%MOD;
val[++cnt]=x+1;val[++cnt]=x+2;
}
val[++cnt]=k;
sort(val+1,val+cnt+1);
cnt=unique(val+1,val+cnt+1)-val-1;
Matrix ans(2,1);
ans.num[0][0]=1%MOD;
ll last=1;
for(int i=1;i<=cnt;i++) {
ll x=val[i];
if (last+1<x) {
ll l=last+1,r=x-1;
if ((l-1)/n!=(r-1)/n) {
ans=rmul[(l-1)%n+1]*ans;
if ((l-1)/n+1<(r-1)/n) ans=(all^((r-1)/n-(l-1)/n-1))*ans;
ans=lmul[(r-1)%n+1]*ans;
}
else ans=SGT::query(1,n,1,(l-1)%n+1,(r-1)%n+1)*ans;
}
Matrix cur(2,2);
cur.num[0][0]=(mp.count(x-1)?mp[x-1]:num[(x-1)%n]%MOD);
cur.num[0][1]=(mp.count(x-2)?mp[x-2]:num[((x-2)%n+n)%n]%MOD);
cur.num[1][0]=1%MOD;
ans=cur*ans;
if (x==k) break;
last=x;
}
printf("%d\n",ans.num[0][0]);
return 0;
}