发现公式里Ax+By+C里面的c是变化的,所以不能直接快速幂,但打个表发现当p/n向下取整的数一定时,n时分段的,即可以将C相同的分段,分段矩阵快速幂
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> using namespace std; typedef __int64 ll; ll a,b,c,d,p,n; const int maxn=1e5+100; const ll mod=1e9+7; const int nn=3; ll f[maxn]; struct maxt { ll m[5][5]; }; maxt mutil(maxt A,maxt B) { maxt temp; memset(temp.m,0,sizeof(temp.m)); for(int i=1; i<=nn; i++) { for(int j=1; j<=nn; j++) { for(int k=1; k<=nn; k++) { temp.m[i][j]=(temp.m[i][j]+A.m[i][k]*B.m[k][j]%mod)%mod; } } } return temp; } maxt quick_mod(maxt a,int b) { maxt r; memset(r.m,0,sizeof(r.m)); for(int i=1; i<=nn; i++) r.m[i][i]=1; while(b) { if(b&1) r=mutil(r,a); a=mutil(a,a); b=b>>1; } return r; } int ct; int main() { maxt t; scanf("%d",&ct); while(ct--) { scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&n); //////////////////////////////////////////////////////////////////// t.m[1][1]=d; t.m[1][2]=c; t.m[1][3]=1; t.m[2][1]=1; t.m[2][2]=0; t.m[2][3]=0; t.m[3][1]=0; t.m[3][2]=0; t.m[3][3]=1; ///////////////////////////////////////////////////////////////////// f[1]=a; f[2]=b; if(p<9)//因为f要从3开始,所以p小于9的要特殊处理 { if(n<3) { printf("%I64d\n",f[n]); continue; } ll mm=max((ll)3,p);//防止p小于3 for(ll i=3; i<=mm; i++)//前p个直接暴力 { f[i]=(c*f[i-2]%mod+d*f[i-1]%mod+(ll)floor(p/i))%mod; } if(n<=mm)//n小于p的话已经求出,直接输出 { printf("%I64d\n",f[n]); continue; } ll f1=f[mm]; ll f2=f[mm-1]; int b=n-mm; if(b>0)//否则对n到p之间的数直接快速幂,因为p/n向下取整都为0,Ax+By+C里面的C是不变的,可以直接快速幂 { ll c=0; maxt tt=quick_mod(t,b); ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod; ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod; f1=ff1; f2=ff2; } printf("%I64d\n",f1); } else//p是大于9的 { ll mm=sqrt(p); for(ll i=3; i<=mm; i++)//对于小于根号p的数直接暴力 { f[i]=(c*f[i-2]%mod+d*f[i-1]%mod+(ll)floor(p/i))%mod; } if(n<=mm) { printf("%I64d\n",f[n]); continue; } ll f1=f[mm]; ll f2=f[mm-1]; for(ll i=sqrt(p)-1; i>=1; i--)//根号p到p的数分段快速幂,因为在每段里的Ax+By+C里面的C是不变的,可以直接快速幂 { int r=p/i; int l=p/(i+1); ll c=i; maxt ff; if(n>=l&&n<=r)//n在段里,可以直接输出 { int b=n-l; maxt tt=quick_mod(t,b); ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod; ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod; f1=ff1; f2=ff2; break; } int b=r-l; maxt tt=quick_mod(t,b); ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod; ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod; f1=ff1; f2=ff2; } int b=n-p;//n是大于p的,则对n到p之间的数直接快速幂 if(b>0) { ll c=0; maxt tt=quick_mod(t,b); ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod; ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod; f1=ff1; f2=ff2; } printf("%I64d\n",f1); } } return 0; }