HDU6050: Funny Function(推公式+矩阵快速幂)

传送门

题意

利用给出的式子求\(F_{m,1}\)

分析

直接推公式(都是找规律大佬)
\(n为偶数,F_{m,1}=\frac{2(2^n-1)^{m-1}}3\)
\(n为奇数,F_{m,1}=F_{m-1,1}(2^n-1)-\frac{2(4^{\frac n2}-1)}3\)
抱歉啊,markdown矩阵相乘实在调不出来了,勉强看一看吧QAQ
\( \left[ \begin{matrix} 2^n-1&-1 \\ 0&1 \end{matrix} \right] \tag{3} \)
\( \left[ \begin{matrix} F_{m-1,1} \\ \frac{2(4^{\frac n2}-1)}3 \end{matrix} \right] \tag{3} \) \(=\) \( \left[ \begin{matrix} F_{m,1}\\ \frac{2(4^{\frac n2}-1)}3 \end{matrix} \right] \tag{3} \)

做一次矩阵快速幂即可

trick

m为1,n为偶数直接输出1

代码

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define F(i,a,b) for(int i=a;i<=b;++i)
#define R(i,a,b) for(int i=a;i<b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
const int N = 2;
const ll mod = 1e9+7;
int t;
ll n,m,n_2,n_4,ni_3;
struct matrix
{
    ll mp[N][N];
    matrix()
    {
        mem(mp,0);
    }
};

ll pow_mod(ll a,ll p)
{
    ll ans=1;
    for(ll ret=a%mod;p;p>>=1,ret=ret*ret%mod) if(p&1) ans=ans*ret%mod;
    return ans;
}
matrix mul(matrix a,matrix b)//矩阵相乘
{
    matrix ans;
    R(i,0,2)R(j,0,2)R(k,0,2) (ans.mp[i][j]+=a.mp[i][k]*b.mp[k][j]%mod)%=mod;
    return ans; 
}
matrix matrix_pow_mod(matrix a,ll p)
{
    matrix ans,ret;
    R(i,0,2)R(j,0,2) ret.mp[i][j]=a.mp[i][j];
    ans.mp[0][0]=ans.mp[1][1]=1;
    while(p)
    {
        if(p&1) ans=mul(ans,ret);
        ret=mul(ret,ret);
        //R(i,0,2)R(j,0,2) printf("%I64d%c", ret.mp[i][j],j==1?'\n':' ');
        p>>=1;
    }
    return ans;
}
void init()
{
    n_2=(pow_mod(2LL,(ll)n)-1+mod)%mod;//求2^n-1
    n_4=(pow_mod(4LL,(ll)(n/2))-1+mod)%mod;//求4^n-1
    ni_3=pow_mod(3LL,mod-2);//求3的逆元
    n_4=n_4*2%mod*ni_3%mod;
}

void work1()
{
    matrix temp,ret;
    temp.mp[0][0]=n_2,temp.mp[0][1]=-1;
    temp.mp[1][0]=0,temp.mp[1][1]=1;
    ret=matrix_pow_mod(temp,(ll)(m-1));//矩阵快速幂
    ll ans=0;
    //R(i,0,2)R(j,0,2) printf("%I64d\n",ret.mp[i][j] );
    ans=(ret.mp[0][0]+ret.mp[0][1]*n_4%mod+mod)%mod;
    while(ans<0) ans+=mod;
    printf("%I64d\n",ans );
}

void work2()
{
    ll ans=pow_mod(n_2,(ll)(m-1));
    ans=ans*2%mod*ni_3%mod;
    ans=(ans+mod)%mod;
    printf("%I64d\n",ans );
}

int main()
{
    for(scanf("%d",&t);t--;)
    //F(i,1,10)F(j,1,10)
    {
        scanf("%lld %lld",&n,&m);
        //n=i,m=j;printf("n=%I64d m=%I64d\n",n,m );
        init();
        if(m==1) { puts("1");continue; }
        if(n&1) work1();else work2();
    }
    return 0;
}
posted @ 2017-08-02 11:28  遗风忘语  阅读(229)  评论(0编辑  收藏  举报