您的位置:首页 > 其它

寺庙逃脱

2016-05-19 20:53 381 查看

题目大意

有q个询问,每个询问给出

给出a[0]=k,和递推式

a[n]=A∗a[n−1]+BC∗a[n−1]+D

求a
mod p的值。

数据范围q<=104,n<=1018,p<=109,|A,B,C,D|<p,保证p为素数

矩阵乘法

a[n+1]=A∗a[n]+BC∗a[n]+D

考虑往下代入递推式

a[n+1]=A∗A∗a[n−1]+BC∗a[n−1]+D+BC∗A∗a[n−1]+BC∗a[n−1]+D+D

分子分母同时乘上C*a[n-1]+D,于是

a[n+1]=A∗(A∗a[n−1]+B)+B∗(C∗a[n−1]+D)C∗(A∗a[n−1]+B)+D∗(C∗a[n−1]+D)

提出a[n-1]

a[n+1]=(A2+B∗C)∗a[n−1]+A∗B+B∗D(A∗C+D∗C)∗a[n−1]+B∗C+D2

容易发现A,B,C,D的转移矩阵是固定的。

然后就可以用矩阵乘法加快速幂。

逆元就随意搞搞就行啦。

代码

我脑残打成了4*4的转移矩阵,其实2*2的就行了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
ll n,k,a,b,c,d,p;
int read(ll &n){
char ch=getchar();
while((ch!='-')&&((ch<'0')||(ch>'9')))ch=getchar();
ll q=0,w=1;if(ch=='-')w=-1,ch=getchar();
while(ch>='0' && ch<='9')q=q*10+ch-48,ch=getchar();n=q*w;
}
struct ju{
ll w[5][5];
} f,g,one;
ju operator *(ju a,ju b){
ju c;
memset(c.w,0,sizeof(c.w));
for (int i=1;i<=4;i++)
for (int k=1;k<=4;k++)
for (int j=1;j<=4;j++) {
c.w[i][k]=(c.w[i][k]+a.w[i][j]*b.w[j][k]%p)%p;
}
return c;
}
ll qss(ll x,ll y){
if (y==0) return 1;
if (y==1) return x;
ll s=qss(x,y/2);s=s*s%p;
if (y%2==0) return s;
s=s*x%p;return s;
}
ju qs(ju g,ll y){
if (y==0) return one;
if (y==1) return g;
ju c=qs(g,y/2);c=c*c;
if (y%2==0) return c;
c=c*g;return c;
}
int main(){
one.w[1][1]=one.w[2][2]=one.w[3][3]=one.w[4][4]=1;
ll q;read(q);
for (q=q;q>0;q--){
read(k);read(a);read(b);read(c);read(d);read(n);read(p);
if (n==0){printf("%lld",k);continue;}
a=(a+p)%p;b=(b+p)%p;c=(c+p)%p;d=(d+p)%p;
memset(g.w,0,sizeof(g.w));memset(f.w,0,sizeof(f.w));
f.w[1][1]=a;f.w[1][2]=b;f.w[1][3]=c;f.w[1][4]=d;
g.w[1][1]=a;g.w[1][2]=b;g.w[1][3]=g.w[2][1]=g.w[2][4]=c;
g.w[2][2]=g.w[3][3]=g.w[4][4]=d;
g=qs(g,n-1);
f=f*g;
ll s1=(f.w[1][1]*k+f.w[1][2])%p,s2=(f.w[1][3]*k+f.w[1][4])%p;
s2=qss(s2,p-2);
printf("%lld\n",s1*s2%p);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: