BZOJ 3240 [Noi2013]矩阵游戏 ——费马小定理 快速幂

发现是一个快速幂,然而过不去。

怎么办呢?

1.十进制快速幂,可以用来练习卡时。

2.费马小定理,如果需要乘方的地方,可以先%(p-1)再计算,其他地方需要%p,所以需要保存两个数。

然后就是分类讨论a是否为1(等比数列求和时要求a不为1)

然后就是递推了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
#define F(i,j,k) for (ll i=j;i<=k;++i)
#define D(i,j,k) for (ll i=j;i>=k;--i)
#define ll long long
const ll md=1000000007;
ll n1,m1,n2,m2,a,b,c,d,len,ans;
char s1[1000005],s2[1000005];
ll qpow(ll a,ll b)
{
    ll ret=1;
    while (b)
    {
        if (b&1) (ret*=a)%=md;
        (a*=a)%=md;
        b>>=1;
    }
    return ret;
}
ll inv(ll a)
{return qpow(a,md-2);}
int main()
{
    scanf("%s",s1+1);
    scanf("%s",s2+1); 
    len=strlen(s1+1); F(i,1,len) n1=(n1*10+s1[i]-'0')%(md-1);
    len=strlen(s2+1); F(i,1,len) m1=(m1*10+s2[i]-'0')%(md-1);
    len=strlen(s1+1); F(i,1,len) n2=(n2*10+s1[i]-'0')%md;
    len=strlen(s2+1); F(i,1,len) m2=(m2*10+s2[i]-'0')%md;
    scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    if (a!=1)
    {
        ll e,f;
        e=(qpow(a,m1-1)*c)%md;
        f=(((((qpow(a,m1-1)-1+md)%md*b)%md*c)%md*inv(a-1))%md+d)%md;
        if (e==1)
        {
            ll tmp=(1LL+f*n2)%md;
            ans=((tmp-d+md)%md*inv(c))%md;
        }
        else
        {
            ll tmp=qpow(e,n1)+(((qpow(e,n1)-1+md)%md*f)%md*inv((e-1+md)%md))%md;
            ans=((tmp-d+md)%md*inv(c))%md;
        }
    }
    else
    {
        ll e,f;
        e=c; f=(((c*b)%md*(m2-1))%md+d)%md;
        if (e==1)
        {
            ll tmp=(1LL+f*n2)%md;
            ans=((tmp-d+md)%md*inv(c))%md;
        }
        else
        {
            ll tmp=qpow(e,n1)+(((qpow(e,n1)-1+md)%md*f)%md*inv((e-1+md)%md))%md;
            ans=((tmp-d+md)%md*inv(c))%md;
        }
    }
    printf("%lld
",ans);
}