Description
F[0]=0,F[1]=1,F[n]=s[n-2]*F[n-2]+s[n-1]*F[n-1],n>=2,s序列是一个循环节为n的序列,但是有m个s[i]的值不等于s[i%n] (i>=n),求F[K]%p
Input
第一行两个整数K和p表示求F[K]%p的值,然后输入一整数n表示s序列循环节,之后输入n个整数表示s[0]~s[n-1],再输入一整数m表示s序列中m个奇异点个数,最后输入m对整数x,y表示s[x]=y
(1<=n,m<=5e4,0<=K<=1e18,1<=p<=1e9,1<=s[i],y<=1e9,n<=x<=1e9)
Output
输出F[K]%p的值
Sample Input
10 8
3
1 2 1
2
7 3
5 4
Sample Output
4
Solution
令,问题变成求K-1个矩阵的乘积,这些矩阵本来应该是由A(0),…,A(n-1)组成,但是由于那些奇异点的存在使得中间有一部分矩阵发生了变化,假设变化后的矩阵为B(i),如果改变s(i)的值,那么会影响到B(i-1)和B(i),求出这些变化的矩阵以及变化的位置,那么这个矩阵序列就变成若干正常的由A(0)~A(n-1)组成的段以及这些奇异点,对于每一正常段,由于都是由循环A(0)~A(n-1)循环得到的,用线段树维护一下A(0),…,A(n-1),A(0),…,A(n-1) 区间积(之所以对两倍的A序列维护是因为起点不一定是A(0)),那么对于一个正常段[L,R),如果R-L>=n,说明该段出现了至少一段完整的A(0)~A(n-1),分成两部分去处理,第一部分是前面的循环部分,设k=(R-L)/n,r=(R-L)%n,求出一段的矩阵积为C=query(L%n,L%n+n-1),然后对该结果做矩阵快速幂C=C^k,剩余的一段为D=query(R%n+n-r,R%n+n-1),那么这块的结果就是C*D;如果R-L < n,若L%n < R%n,那么答案就是query(L%n,R%n-1),否则答案就是(L%n,R%n+n-1),知道了每一个正常段的答案和分隔开正常段的奇异点的值,按顺序乘起来即为最终答案
Code
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
#define maxn 111111
typedef long long ll;
int n,m;
ll K,p,s[maxn];
map<ll,ll>M;
map<ll,ll>::iterator it;
struct Mat
{
ll mat[2][2];//矩阵
Mat()
{
memset(mat,0,sizeof(mat));
}
Mat operator *(const Mat &b)const
{
Mat ans;
for(int i=0;i<2;i++)
for(int k=0;k<2;k++)
for(int j=0;j<2;j++)
ans.mat[i][j]=(ans.mat[i][j]+mat[i][k]*b.mat[k][j]%p)%p;
return ans;
}
};
Mat mod_pow(Mat a,ll k)//矩阵快速幂
{
Mat ans;
ans.mat[0][0]=ans.mat[1][1]=1;
while(k)
{
if(k&1)ans=ans*a;
a=a*a;
k>>=1;
}
return ans;
}
Mat Get_M(ll x,ll y)
{
Mat ans;
ans.mat[0][0]=0,ans.mat[0][1]=x,
ans.mat[1][0]=1,ans.mat[1][1]=y;
return ans;
}
ll Get_S(ll x)
{
if(M.find(x)!=M.end())return M[x];
return s[x%n];
}
Mat A[maxn<<2];
#define ls (t<<1)
#define rs ((t<<1)|1)
void push_up(int t)
{
A[t]=A[ls]*A[rs];
}
void build(int l,int r,int t)
{
if(l==r)
{
A[t]=Get_M(s[l],s[l+1]);
return ;
}
int mid=(l+r)/2;
build(l,mid,ls),build(mid+1,r,rs);
push_up(t);
}
Mat query(int L,int R,int l,int r,int t)
{
if(L<=l&&r<=R)return A[t];
int mid=(l+r)/2;
Mat ans;
ans.mat[0][0]=ans.mat[1][1]=1;
if(L<=mid)ans=ans*query(L,R,l,mid,ls);
if(R>mid)ans=ans*query(L,R,mid+1,r,rs);
return ans;
}
Mat Query(ll L,ll R)
{
Mat ans,temp;
if(R-L>=n)
{
ll k=(R-L)/n,r=(R-L)%n;
temp=query(L%n,L%n+n-1,0,2*n-1,1);
ans=mod_pow(temp,k);
if(r)ans=ans*query(R%n+n-r,R%n+n-1,0,2*n-1,1);
}
else
{
if(L%n<R%n)ans=query(L%n,R%n-1,0,2*n-1,1);
else ans=query(L%n,R%n+n-1,0,2*n-1,1);
}
return ans;
}
ll pos[maxn];
Mat B[maxn];
int main()
{
while(~scanf("%I64d%I64d",&K,&p))
{
M.clear();
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&s[i]),s[i+n]=s[i];
scanf("%d",&m);
for(int i=0;i<m;i++)
{
ll x,y;
scanf("%I64d%I64d",&x,&y);
M[x]=y;
}
if(K==0||p==1)
{
printf("0\n");
continue;
}
int cnt=0;
for(it=M.begin();it!=M.end();it++)
{
ll x=it->first,y=it->second;
if(!cnt||x>pos[cnt-1]+1)
{
if(x-1<K-1)pos[cnt]=x-1,B[cnt++]=Get_M(Get_S(x-1),y);
}
if(x<K-1)pos[cnt]=x,B[cnt++]=Get_M(y,Get_S(x+1));
}
pos[cnt]=K-1,B[cnt++]=Get_M(Get_S(K-1),Get_S(K));
build(0,2*n-1,1);
Mat ans;
ans.mat[0][0]=ans.mat[1][1]=1;
ll pre=0;
for(int i=0;i<cnt;i++)
{
if(pos[i]>pre)ans=ans*Query(pre,pos[i]);
ans=ans*B[i];
pre=pos[i]+1;
}
printf("%I64d\n",ans.mat[1][0]);
}
return 0;
}