bzoj 3240 (洛谷P1397): [Noi2013]矩阵游戏 (欧拉定理、数学)

题意

F(i,j)=1F(i,j)=aF(i,j1)+bF(i,1)=cF(i1,m)+di=1,j=1j1i1 F ( i , j ) = { 1 i = 1 , j = 1 F ( i , j ) = a ⋅ F ( i , j − 1 ) + b j ≠ 1 F ( i , 1 ) = c ⋅ F ( i − 1 , m ) + d i ≠ 1

已知 abcdnm a 、 b 、 c 、 d 、 n 、 m ,求 F(n,m) F ( n , m )


题解

我们先来化简这个式子

通过第一个式子,我们可以得到 f(i,m)=am1f(i,1)+(am2+am3+a+1)b f ( i , m ) = a m − 1 f ( i , 1 ) + ( a m − 2 + a m − 3 + ⋯ a + 1 ) b

重新考虑答案

f(n,m)=am1f(n,1)+(am2+am3+a+1)b=am1(cf(n1,m)+d)+(am2+am3+a+1)b=am1cf(n1,m)+am1d+(am2+am3+a+1)b f ( n , m ) = a m − 1 f ( n , 1 ) + ( a m − 2 + a m − 3 + ⋯ a + 1 ) b = a m − 1 ( c ⋅ f ( n − 1 , m ) + d ) + ( a m − 2 + a m − 3 + ⋯ a + 1 ) b = a m − 1 c ⋅ f ( n − 1 , m ) + a m − 1 d + ( a m − 2 + a m − 3 + ⋯ a + 1 ) b

简化一波…令 p=(am2+am3++a+1)b p = ( a m − 2 + a m − 3 + ⋯ + a + 1 ) b x=am1c x = a m − 1 c y=am1d+p y = a m − 1 d + p q=(xn2+xn3++x+1)y q = ( x n − 2 + x n − 3 + ⋯ + x + 1 ) y (后面会有用)

那么,原式就等于

f(n,m)=am1cf(n1,m)+am1d+(am2+am3+a+1)b=xf(n1,m)+y=x(am1f(n1,1)+p)+y=xam1f(n1,1)+xp+y=xam1(cf(n2,m)+d)+xp+y=xam1cf(n2,m)+xam1d+xp+y=x2f(n2,m)+(x+1)y=xn1f(1,m)+(xn2+xn3++x+1)y=am1xn1+xn1p+q f ( n , m ) = a m − 1 c ⋅ f ( n − 1 , m ) + a m − 1 d + ( a m − 2 + a m − 3 + ⋯ a + 1 ) b = x ⋅ f ( n − 1 , m ) + y = x ( a m − 1 f ( n − 1 , 1 ) + p ) + y = x a m − 1 f ( n − 1 , 1 ) + x p + y = x a m − 1 ( c f ( n − 2 , m ) + d ) + x p + y = x a m − 1 c f ( n − 2 , m ) + x a m − 1 d + x p + y = x 2 f ( n − 2 , m ) + ( x + 1 ) y = x n − 1 f ( 1 , m ) + ( x n − 2 + x n − 3 + ⋯ + x + 1 ) y = a m − 1 x n − 1 + x n − 1 p + q

显然 pq p 、 q 可以用等比数列求出(等比为 1 1 的时候另行讨论)

然而 am1xn1 就不能直接算了

通过费马小定理 a(p1)1 a ( p − 1 ) ≡ 1 (mod ( m o d p) p ) , 所以 ap=a(pmod(k1))(modk) a p = a ( p m o d ( k − 1 ) ) ( m o d k )


代码

#include <cstdio>
#include <cstring>
#define mod 1000000007
#define N 1000005
#define ll long long
char str1[N];
int n,m,n1,m1,a,b,c,d;
int qpow(int x,int y){
    int t=1;
    while(y){
        if(y&1) t=(ll)t*x%mod;
        x=(ll)x*x%mod;y>>=1; 
    }return t;
}
int main(){
    freopen("a.in","r",stdin);

    scanf("%s",str1+1);
    n=0,n1=0;int nn=strlen(str1+1);
    for(int i=1;i<=nn;i++) n=((ll)n*10+str1[i]-'0')%(mod-1),n1=((ll)n1*10+str1[i]-'0')%mod;
    n=(n-1+mod-1)%(mod-1);n1=(n1-1+mod)%mod;
    scanf("%s",str1+1);
    m=0,m1=0;nn=strlen(str1+1);
    for(int i=1;i<=nn;i++) m=((ll)m*10+str1[i]-'0')%(mod-1),m1=((ll)m1*10+str1[i]-'0')%mod;
    m=(m-1+mod-1)%(mod-1);m1=(m1-1+mod)%mod;

    scanf("%d%d%d%d",&a,&b,&c,&d);
    int am=qpow(a,m),x=(ll)am*c%mod,p;
    if(a==1) p=(ll)m1*b%mod;
    else p=(ll)b*(am-1+mod)%mod*qpow(a-1,mod-2)%mod;
    int xn=qpow(x,n),y=((ll)am*d%mod+p)%mod,q;
    if(x==1) q=(ll)n1*y%mod;
    else q=(ll)y*(xn-1+mod)%mod*qpow(x-1,mod-2)%mod;

    printf("%d\n",(((ll)am*xn%mod+(ll)xn*p%mod)%mod+q)%mod);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值