P1397 [NOI2013]矩阵游戏

传送门

首先显然可以矩乘快速幂然后 $T$ 飞

看一眼题解发现因为这一题矩阵的特殊性所以可以对矩阵的次数欧拉降幂

然而我并不懂证明,所以我选择暴力乱搞的做法

十进制快速幂,然后注意一下常数,还有矩阵乘的顺序,别反了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=1e6+7,mo=1e9+7;
char n[N],m[N];
struct Matrix {
    int a[3][3];
    Matrix () { memset(a,0,sizeof(a)); }
    inline Matrix operator * (const Matrix &tmp) const {
        Matrix res;
        res.a[1][1]=(1ll*a[1][1]*tmp.a[1][1]+1ll*a[1][2]*tmp.a[2][1])%mo;
        res.a[1][2]=(1ll*a[1][1]*tmp.a[1][2]+1ll*a[1][2]*tmp.a[2][2])%mo;
        res.a[2][1]=(1ll*a[2][1]*tmp.a[1][1]+1ll*a[2][2]*tmp.a[2][1])%mo;
        res.a[2][2]=(1ll*a[2][1]*tmp.a[1][2]+1ll*a[2][2]*tmp.a[2][2])%mo;
        //循环展开优化常数
        return res;
    }
}F,G,Ans;
Matrix ksm(Matrix x,char *y)//十进制快速幂
{
    Matrix res,t; res.a[1][1]=res.a[2][2]=1;
    for(int i=strlen(y+1);i;i--)
    {
        t=x;
        if(y[i]=='9') { t=t*t; t=t*t; t=t*t; t=t*x; res=res*t; }
        else if(y[i]=='8') { t=t*t; t=t*t; t=t*t; res=res*t; }
        else for(int j=1;j<=y[i]-'0';j++) res=res*x;
        t=x; x=x*x; x=x*x; x=x*x; x=x*t; x=x*t;
    }
    return res;
}
void Minus(char *s)//把数减一
{
    for(int i=strlen(s+1);i;i--)
        if(s[i]=='0') s[i]='9';
        else { s[i]=s[i]-1; break; }
}
int main()
{
    int a,b,c,d; scanf("%s",n+1); scanf("%s",m+1);
    a=read(),b=read(),c=read(),d=read();
    Ans.a[1][1]=Ans.a[1][2]=1;
    F.a[1][1]=a; F.a[2][1]=b; F.a[2][2]=1;
    G.a[1][1]=c; G.a[2][1]=d; G.a[2][2]=1;
    Minus(n); Minus(m);
    F=ksm(F,m); G=F*G; G=ksm(G,n);
    Ans=Ans*G*F;
    printf("%d\n",Ans.a[1][1]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LLTYYC/p/11521638.html