题目:
题解:
NOI老是考奇奇怪怪的数学题诶。。。
解法一:
p,q都可以使用等比数列求和公式计算(注意若公比为1,不能使用求和公式)
代码:
#include <cstdio>
#include <cstring>
using namespace std;
const int mod=1e9+7;
#define LL long long
const int N=1000005;
char stn[N],stm[N];
LL ksm(LL a,LL k,int mod)
{
LL ans=1;
for (;k;k>>=1,a=a*a%mod)
if (k&1) ans=ans*a%mod;
return ans;
}
int main()
{
freopen("matrixb.in","r",stdin);
freopen("matrixb.out","w",stdout);
LL n=0,n1=0,m=0,m1=0,a,b,c,d;scanf("%s",stn); scanf("%s",stm);
int sb=strlen(stn),st=strlen(stm);
for (int i=0;i<sb;i++)
{
n=n*10+stn[i]-'0';
if (n>=mod) n%=mod;
n1=n1*10+stn[i]-'0';
if (n1>=mod-1) n1%=(mod-1);
}
n=(n-1+mod)%mod;
n1=(n1-1+mod-1)%(mod-1);
for (int i=0;i<st;i++)
{
m=m*10+stm[i]-'0';
if (m>=mod) m%=mod;
m1=m1*10+stm[i]-'0';
if (m1>=mod-1) m1%=(mod-1);
}
m=(m-1+mod)%mod;
m1=(m1-1+mod-1)%(mod-1);
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
LL p,x,y,q,inv;
if (a==1) p=b*m%mod;
else inv=ksm(a-1,mod-2,mod),p=b*(ksm(a,m1,mod)-1)%mod*inv%mod;
x=ksm(a,m1,mod)*c%mod;
y=ksm(a,m1,mod)*d%mod+p;y%=mod;
if (x==1) q=y*n%mod;
else inv=ksm(x-1,mod-2,mod),q=y*(ksm(x,n1,mod)-1)%mod*inv%mod;
LL ans=ksm(x,n1,mod)*(ksm(a,m1,mod)%mod+p)%mod+q;
printf("%lld",ans%mod);
}
解法二:
解法一是数学做法,然而我们也可以用矩阵快速幂解决这个问题
设矩阵A3为
1 1
矩阵A1为
a 0
b 1
矩阵A2为
c 0
d 1
那么转移到n行m列应该是: A3Am−11(A2Am−11)n−1 A 3 A 1 m − 1 ( A 2 A 1 m − 1 ) n − 1
对于指数上很大的数字,这是矩阵不能用费马小定理,可以使用十进制快速幂,这种方法就是若是求x的y次方,从低位到高位查看y十进制下的每一位,这一位为几,就让ans乘几个x,然后让 x=x10 x = x 10 ,不断这样操作即可。
卡常数卡到怀疑人生= =
不用longlong会快,怕爆就*1LL;小的乘数不用快速幂。
代码:
#include <cstdio>
#include <cstring>
using namespace std;
const int mod=1e9+7;
const int N=1000005;
char n[N],m[N];
struct mat{int sq[5][5];}a1,a2;
mat operator *(mat a,mat b)
{
mat c;
c.sq[1][1]=(1LL*a.sq[1][1]*b.sq[1][1]%mod+1LL*a.sq[1][2]*b.sq[2][1]%mod)%mod;
c.sq[1][2]=(1LL*a.sq[1][1]*b.sq[1][2]%mod+1LL*a.sq[1][2]*b.sq[2][2]%mod)%mod;
c.sq[2][1]=(1LL*a.sq[2][1]*b.sq[1][1]%mod+1LL*a.sq[2][2]*b.sq[2][1]%mod)%mod;
c.sq[2][2]=(1LL*a.sq[2][1]*b.sq[1][2]%mod+1LL*a.sq[2][2]*b.sq[2][2]%mod)%mod;
return c;
}
mat ksm10(mat a,char *n)
{
mat ans;
ans.sq[1][1]=ans.sq[2][2]=1;
ans.sq[1][2]=ans.sq[2][1]=0;
int sb=strlen(n+1);
for (int i=sb;i>=1;i--)
{
int x=n[i]-'0';mat tmp=a;
if (n[i]=='9') tmp=tmp*tmp,tmp=tmp*tmp,tmp=tmp*tmp,tmp=tmp*a,ans=ans*tmp;
else if (n[i]=='8') tmp=tmp*tmp,tmp=tmp*tmp,tmp=tmp*tmp,ans=ans*tmp;
else for (int j=1;j<=n[i]-'0';j++) ans=ans*tmp;
tmp=a;tmp=tmp*tmp,tmp=tmp*tmp,tmp=tmp*tmp,tmp=tmp*a,tmp=tmp*a;
a=tmp;
}
return ans;
}
int main()
{
scanf("%s",n+1); scanf("%s",m+1);
scanf("%d%d%d%d",&a1.sq[1][1],&a1.sq[2][1],&a2.sq[1][1],&a2.sq[2][1]);
int sb=strlen(n+1);
for (int i=sb;i>=1;i--)
if (n[i]=='0') n[i]='9';else {n[i]=n[i]-1; break;}
sb=strlen(m+1);
for (int i=sb;i>=1;i--)
if (m[i]=='0') m[i]='9';else {m[i]=m[i]-1; break;}
a1.sq[2][2]=1; a2.sq[2][2]=1;
a1=ksm10(a1,m);
a2=ksm10(a2*a1,n);
a1=a1*a2;
printf("%d",(a1.sq[1][1]+a1.sq[2][1])%mod);
}