HDU 6172 Array Challenge 【线性递推式模板】

来源:互联网 发布:光电转换器淘宝网 编辑:程序博客网 时间:2024/06/02 02:21


Array Challenge

Time Limit: 2000/1000 MS(Java/Others)    Memory Limit: 153428/153428 K(Java/Others)
Total Submission(s): 572    Accepted Submission(s): 323

Problem Description

There’s an array that isgenerated by following rule.
h0=2,h1=3,h2=6,hn=4hn−1+17hn−2−12hn−3−16
And let us define two arrays
bn and an asbelow.
bn=3hn+1hn+9hn+1hn−1+9h2n+27hnhn−1−18hn+1−126hn−81hn−1+192(n>0)
an=bn+4n
Now, you have to print
⌊√(an)⌋,n>1.
Your answer could be very large so print the answer modular 1000000007.
 

 

Input

The first line of inputcontains T (1 <= T <= 1000) , the number of test cases.
Each test case contains one integer n (1 < n <=
1015) in one line.

  

Output

For each test case print&#8970;√(a_n )&#8971; modular 1000000007.

  

Sample Input

3

4

7

9

  

Sample Output

1255

324725

13185773



【题意】


略。


【思路】


这道题可以用找规律得到一个表达式,然后利用矩阵快速幂求解。


但是这里要介绍的是一种黑科技,对于线性递推式,我们只要输入前几项,就能得到第n项。


该“黑科技”的模板见下面的代码。


PS:输入前几项的项数最好大于8项,且项数越多,结果越准确。



#include <cstdio>#include <cassert>#include <queue>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))#define rush() int T;scanf("%d",&T);while(T--)typedef long long ll;typedef vector<int> VI;const int maxn = 10005;const ll mod = 1e9+7;const int INF = 0x3f3f3f3f;const double eps = 1e-9;ll fast_mod(ll a,ll n,ll Mod){    ll ans=1;    a%=Mod;    while(n)    {        if(n&1) ans=(ans*a)%Mod;        a=(a*a)%Mod;        n>>=1;    }    return ans;}namespace linear_seq{    ll res[maxn],base[maxn],num[maxn],md[maxn];  //数组大小约10000    vector<int>vec;    void mul(ll *a,ll *b,int k)    {        for(int i=0;i<2*k;i++) num[i]=0;        for(int i=0;i<k;i++)        {            if(a[i])            {                for(int j=0;j<k;j++)                {                    num[i+j]=(num[i+j]+a[i]*b[j])%mod;                }            }        }        for(int i=2*k-1;i>=k;i--)        {            if(num[i])            {                for(int j=0;j<vec.size();j++)                {                    num[i-k+vec[j]]=(num[i-k+vec[j]]-num[i]*md[vec[j]])%mod;                }            }        }        for(int i=0;i<k;i++) a[i]=num[i];    }    ll solve(ll n,VI a,VI b)    {        ll ans=0,cnt=0;        int k=a.size();        assert(a.size()==b.size());        for(int i=0;i<k;i++) md[k-1-i]=-a[i];        md[k]=1;        vec.clear();        for(int i=0;i<k;i++) if(md[i]) vec.push_back(i);        for(int i=0;i<k;i++) res[i]=base[i]=0;        res[0]=1;        while((1LL<<cnt)<=n) cnt++;        for(int p=cnt;p>=0;p--)        {            mul(res,res,k);            if((n>>p)&1)            {                for(int i=k-1;i>=0;i--) res[i+1]=res[i];                res[0]=0;                for(int j=0;j<vec.size();j++)                {                    res[vec[j]]=(res[vec[j]]-res[k]*md[vec[j]])%mod;                }            }        }        for(int i=0;i<k;i++) ans=(ans+res[i]*b[i])%mod;        if(ans<0) ans+=mod;        return ans;    }    VI BM(VI s)    {        VI B(1,1),C(1,1);        int L=0,m=1,b=1;        for(int i=0;i<s.size();i++)        {            ll d=0;            for(int j=0;j<L+1;j++) d=(d+(ll)C[j]*s[i-j])%mod;            if(d==0) m++;            else if(2*L<=i)            {                VI T=C;                ll c=mod-d*fast_mod(b,mod-2,mod)%mod;                while(C.size()<B.size()+m) C.push_back(0);                for(int j=0;j<B.size();j++) C[j+m]=(C[j+m]+c*B[j])%mod;                L=i+1-L,B=T,b=d,m=1;            }            else            {                ll c=mod-d*fast_mod(b,mod-2,mod)%mod;                while(C.size()<B.size()+m) C.push_back(0);                for(int j=0;j<B.size();j++) C[j+m]=(C[j+m]+c*B[j])%mod;                m++;            }        }        return C;    }    int gao(VI a,ll n)    {        VI c=BM(a);        c.erase(c.begin());        for(int i=0;i<c.size();i++) c[i]=(mod-c[i])%mod;        return solve(n,c,VI(a.begin(),a.begin()+c.size()));    }}int main(){    ll n;    rush()    {        scanf("%I64d",&n);        printf("%d\n",linear_seq::gao(VI{31,197,1255,7997,50959,324725,2069239,13185773,84023455},n-2));    }    return 0;}