hdu 6050 Funny Function

 /*
  打表找到公式,矩阵快速幂加速- -
  马虎:ll 类型  写成int , 一直 wrong T.T 
 1-7^n / 1-7 
f(n) =2^(n-1)+f(n-2)
 */ 
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;
typedef long long ll;
const int mod =1e9+7;
struct mex
{
    int a[4][4];
}m1[6];
mex Plus(mex a,mex b)
{
    mex c;ll d;
    memset(c.a,0,sizeof(c.a));
    for(int i=1;i<=3;++ i)
     for(int j=1;j<=3;++ j)
      for(int k=1;k<=3; ++ k)
        {
            
            d=a.a[i][k];
            d *=b.a[k][j];
            d %=mod;
            c.a[i][j] =(c.a[i][j]+d)%mod;
        }
      return c;
}
ll quickm(ll n,ll m)  
{  
    ll a=1,x=n;  
    while(m)  
    {  
        if(m&1) a =(a*x)%mod;  
        x=(x*x)%mod;  
        m /=2;  
    }  
    return a%mod;  
}  
void gcd(ll a,ll b,ll &d,ll &x,ll &y)  
{  
    if(!b) {d=1;x=1;y=0;}  
    else  
    {  
        gcd(b,a%b,d,y,x); y-= x*(a/b);  
    }  
}  
int inc(int a,int mod)  
{  
    ll x,y,d;  
    gcd(a,mod,d,x,y);  
    return d==1?(x+mod)%mod:-1;  
}
void init()
{
    m1[1].a[1][1]=1;
    m1[1].a[2][1]=4;
    m1[1].a[3][1]=2;
    memset(m1[2].a,0,sizeof(m1[2].a));
    m1[2].a[1][3]=1;m1[2].a[3][1]=1;m1[2].a[3][2]=1;
    m1[2].a[2][2]=2;
}
int main()
{
    int t;
    ll n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        ll n0,nn=n;
        if(m==1||n==1) { printf("1\n"); continue;}
        init();
        n0=n-1;n -=2;
        while(n)
        {    
            
            if(n&1) m1[1]=Plus(m1[2],m1[1]);
            m1[2]=Plus(m1[2],m1[2]);
            n /=2;
        }
        int a1=m1[1].a[3][1],a0=0;
        if(n0==1) a0=1;
        if(!a0)
        {
            n=n0;n -=2;
            init();
            while(n)
           {
              if(n&1) m1[1]=Plus(m1[2],m1[1]);
              
              m1[2]=Plus(m1[2],m1[2]);
              n /=2;
           }
           a0=m1[1].a[3][1];
        }
        if(m==2) 
        {
            printf("%d\n",a1);
            continue; 
        }
        int dos=(a0+a1)%mod;
        ll d=quickm(dos,m-2);
        ll ans=(ll)d*a1%mod;
        if(nn%2)
        {
            int ink=inc(dos-1,mod);         
            ll dd =ink;dd *=d-1; dd%=mod; dd *=a0;dd %=mod;
            ans -=dd;
            ans =(ans+mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值