寺庙逃脱

来源:互联网 发布:如何增强勃起硬度知乎 编辑:程序博客网 时间:2024/04/29 22:31

题目大意

有q个询问,每个询问给出
给出a[0]=k,和递推式

a[n]=Aa[n1]+BCa[n1]+D

求a[n] mod p的值。
数据范围q<=104,n<=1018,p<=109,|A,B,C,D|<p,p

矩阵乘法

a[n+1]=Aa[n]+BCa[n]+D

考虑往下代入递推式

a[n+1]=AAa[n1]+BCa[n1]+D+BCAa[n1]+BCa[n1]+D+D

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

a[n+1]=A(Aa[n1]+B)+B(Ca[n1]+D)C(Aa[n1]+B)+D(Ca[n1]+D)

提出a[n-1]

a[n+1]=(A2+BC)a[n1]+AB+BD(AC+DC)a[n1]+BC+D2

容易发现A,B,C,D的转移矩阵是固定的。
然后就可以用矩阵乘法加快速幂。
逆元就随意搞搞就行啦。

代码

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

#include<cstdio>#include<algorithm>#include<cstring>#define ll long longll 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);    }}
0 0