bzoj3240 [Noi2013]矩阵游戏——费马小定理+推式子
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3240
n 和 m 太过巨大,不难想到应该用费马小定理什么的来缩小范围;
总之就是推式子啦,看博客:https://blog.csdn.net/jiangshibiao/article/details/24594825
还有:https://www.cnblogs.com/iiyiyi/p/5617598.html
其实也蛮好推的,也挺好写,但我调了很久很久啊...
要十分注意取 mod 时候加括号的艺术...
还要注意指数里的 n 或 m 取的是 mod-1 的模,就是费马小定理。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; int const maxl=1e6+5; ll a,b,c,d,mod=1e9+7,A,B,tmp; char nn[maxl],mm[maxl]; struct N{ll ord,uni;}n,m; void get() { int l=strlen(nn); // for(int i=l-1;i>=0;i--)//傻了 for(int i=0;i<l;i++) { n.ord=(n.ord*10%mod+nn[i]-'0')%mod;//a=1 n.uni=(n.uni*10%(mod-1)+nn[i]-'0')%(mod-1);//a!=1 } l=strlen(mm); // for(int i=l-1;i>=0;i--) for(int i=0;i<l;i++) { m.ord=(m.ord*10%mod+mm[i]-'0')%mod;//a=1 m.uni=(m.uni*10%(mod-1)+mm[i]-'0')%(mod-1);//a!=1 } } ll pw(ll a,ll b) { ll ret=1; for(;b;b>>=1ll,(a*=a)%=mod) if(b&1) (ret*=a)%=mod; return ret; } ll ni(ll x){return pw(x,mod-2);} int main() { scanf("%s%s",&nn,&mm); scanf("%lld%lld%lld%lld",&a,&b,&c,&d); get(); if(a==1) { B=(((c*b)%mod*(m.ord-1))%mod+d)%mod; if(c==1)tmp=(1+n.ord*B)%mod; else tmp=(pw(c,n.uni)+((B*(pw(c,n.uni)-1)%mod)*ni(c-1))%mod)%mod;//注意指数部分是uni而非ord!!! } else { A=(pw(a,m.uni-1)*c)%mod; B=(((((pw(a,m.uni-1)-1)*ni(a-1))%mod*c)%mod*b)%mod+d)%mod; tmp=(pw(A,n.uni)+(((pw(A,n.uni)-1)*ni(A-1))%mod*B)%mod)%mod; } printf("%lld",((tmp-d)*ni(c)%mod+mod)%mod);//+mod %mod return 0; }