题目大意:
- 定义(f_i=s_{i-1}f_{i-1}+s_{i-2}f_{i-2},f_0=0,f_1=0)。
- 在通常情况下(s_i=s_{i mod n})。
- 有(m)个位置(s_i)特殊给定。
- 求(f_kmod p)。
题目链接:575A. Fibonotci。
题解:由于(kleq 10^{18}),很容易考虑到矩阵快速幂,如果没有特殊位置,可以直接矩阵快速幂做完,特殊位置特殊考虑,如果暴力求特殊位置所在循环节的矩阵值的话,时间复杂度是(O(nm))的,所以考虑用线段树维护转移矩阵,每一次特殊位置就直接单点修改随后改回来,然后就做完了。
但是在实现时会有一个很麻烦的地方,就是一次修改可能会影响到两个循环节,所以需要将特殊位置拆开成两个,在这种情况下,如果是在原序列上修改的话会有很多细节处理起来很麻烦,所以可以在一开始把所有的转移矩阵存下来,每一次对转移矩阵进行修改。
时间复杂度:(O(nlog k))。
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int Maxn=50000;
typedef long long ll;
int n,m;
ll K;
int Mod;
int s[Maxn+5];
struct Operation{
ll pos;
int val,x;
friend bool operator <(Operation p,Operation q){
return p.pos<q.pos;
}
}op[Maxn<<1|5];
struct Matrix{
int a[2][2];
Matrix(){
a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;
}
friend Matrix operator *(Matrix a,Matrix b){
Matrix ans;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
ans.a[i][j]=(ans.a[i][j]+1ll*b.a[i][k]*a.a[k][j])%Mod;
}
}
}
return ans;
}
};
Matrix a[Maxn+5],tmp[Maxn+5],d[Maxn+5];
ll b[Maxn+5];
int len;
Matrix val[Maxn<<2|5];
void insert(int x,Matrix a,int root=1,int left=1,int right=n){
if(left==right){
val[root]=a;
return;
}
int mid=(left+right)>>1;
if(x<=mid){
insert(x,a,root<<1,left,mid);
}
else{
insert(x,a,root<<1|1,mid+1,right);
}
val[root]=(val[root<<1]*val[root<<1|1]);
}
Matrix quick_power(Matrix a,ll b){
Matrix ans;
ans.a[0][0]=ans.a[1][1]=1;
while(b){
if(b&1){
ans=(ans*a);
}
b>>=1;
a=(a*a);
}
return ans;
}
int main(){
scanf("%lld%d",&K,&Mod);
if(K==0){
puts("0");
return 0;
}
if(Mod==1){
puts("0");
return 0;
}
if(K==1){
puts("1");
return 0;
}
scanf("%d",&n);
ll bel_k=K/n;
for(int i=0;i<n;i++){
scanf("%d",&s[i]);
s[i]%=Mod;
}
s[n]=s[0];
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%lld%d",&op[i].pos,&op[i].val);
op[i].pos;
op[i].val%=Mod;
op[i+m]=op[i];
op[i+m].pos++;
op[i].x=1;
}
m<<=1;
sort(op+1,op+1+m);
for(int i=1;i<=n;i++){
a[i].a[0][0]=0;
a[i].a[0][1]=1;
a[i].a[1][0]=s[i-1];
a[i].a[1][1]=s[i];
insert(i,a[i]);
tmp[i]=a[i];
}
while(op[m].pos>K){
m--;
}
Matrix all=val[1];
for(int i=1,j;i<=m;i=j+1){
j=i;
ll bel=(op[i].pos-1)/n;
while(j<m&&bel==(op[j+1].pos-1)/n){
j++;
}
for(int k=i;k<=j;k++){
int pos=(op[k].pos-1)%n+1;
tmp[pos].a[1][op[k].x]=op[k].val;
insert(pos,tmp[pos]);
}
if(bel==bel_k){
break;
}
d[++len]=val[1];
b[len]=bel;
for(int k=i;k<=j;k++){
int pos=(op[k].pos-1)%n+1;
tmp[pos]=a[pos];
insert(pos,a[pos]);
}
}
Matrix ans;
ans.a[0][0]=ans.a[1][1]=1;
ll last=0;
for(int i=1;i<=len;i++){
ans=ans*quick_power(all,b[i]-last);
ans=ans*d[i];
last=b[i]+1;
}
ans=ans*quick_power(all,bel_k-last);
for(int i=1;i<=K%n;i++){
ans=ans*tmp[i];
}
printf("%d
",ans.a[0][1]);
return 0;
}