HDU 6395 2018 Multi-University Training Contest 7 (快速幂+分块)

原题地址

Sequence

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1186    Accepted Submission(s): 433


Problem Description
Let us define a sequence as below

⎧⎩⎨⎪⎪⎪⎪⎪⎪F1F2Fn===ABCFn2+DFn1+Pn


  Your job is simple, for each task, you should output Fn module 109+7.
 

 

Input
The first line has only one integer  T, indicates the number of tasks.

Then, for the next T lines, each line consists of 6 integers, A , BCDPn.

1T200A,B,C,D1091P,n109
 

 

Sample Input
2 3 3 2 1 3 5 3 2 2 2 1 4
 

 

Sample Output
36 24
 

 

Source
 

 

Recommend
 
矩阵快速幂,但是中间带着一个跟着N变化的值;一开始想直接硬构造出一个矩阵;发现行不通就和队友搞其他题了;
后来发现这P/n在每个sqrt(q)范围内都是一定的;所以可以试着查找p/n这个值最大到哪一项,然后分别快速幂;很神奇的就是为什么p/(p/i)就是这个p/i的最大项;到现在还不明白‘
我的矩阵
 
Fn    D C p/i     Fn-1
Fn-1   1  0  0      Fn-2
1      0  0  1        1
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=3e6+50;
const ll inf=0x3f3f3f3f3f3f;
ll a,b,c,d,p,n;
ll k,kk;
ll fun[100000005];
struct node{
    ll a[3][3];
    void init(){
        memset(a,0,sizeof(a));
        for(int i=0;i<3;i++){
            a[i][i]=1;
        }
    }
};
node mul(node a,node b)
{
    node ans;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            ans.a[i][j]=0;
            for(int k=0;k<3;k++){
                ans.a[i][j]+=a.a[i][k]*b.a[k][j];
                ans.a[i][j]%=mod;
            }
        }
    }return ans;
}
void output(node a){
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            cout<<a.a[i][j]<<" ";
        }cout<<endl;
    }
}
node qpow(node a,ll n){
    node ans;
    ans.init();
    while(n){
        if(n&1)ans=mul(ans,a);
        a=mul(a,a);
        n/=2;
    }
    return ans;
}
node ac;
void init(ll d,ll c,ll x){
    ac.a[0][0]=d;ac.a[0][1]=c;ac.a[0][2]=x;   /*ac D C P/I  */
    ac.a[1][0]=1;ac.a[1][1]=0;ac.a[1][2]=0;   /*   1 0 0   */  
    ac.a[2][0]=0;ac.a[2][1]=0;ac.a[2][2]=1;   /*   0 0 1   */ 
}
node anw;
void init2(ll a,ll b){
    anw.a[0][0]=b;anw.a[1][0]=a;anw.a[2][0]=1;  /*fn*/
}                                               /*fn-1*/
node init3(node one,node two){                  /*1*/
    node retu;
    retu.a[0][0]=(one.a[0][0]*two.a[0][0]+one.a[0][1]*two.a[1][0]+one.a[0][2]*two.a[2][0])%mod;
    retu.a[1][0]=(one.a[1][0]*two.a[0][0]+one.a[1][1]*two.a[1][0]+one.a[1][2]*two.a[2][0])%mod;
    retu.a[2][0]=(one.a[2][0]*two.a[0][0]+one.a[2][1]*two.a[1][0]+one.a[2][2]*two.a[2][0])%mod;
    return retu;
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        cin>>a>>b>>c>>d>>p>>n;
        k=p/n;kk=p%n;
        if(n==1){cout<<a<<endl;continue;}
        if(n==2){cout<<b<<endl;continue;}
        else{
            init(d,c,1);
            init2(a,b);
            //output(ac);
           // output(anw);
            for(ll i=3;i<=n;){
                if(p/i==0){
                    ll num=n-i+1;
                    init(d,c,0);
                    node mid=qpow(ac,num);
                    anw=init3(mid,anw);
                    break;
                }
                else{
                    ll k=min(n,p/(p/i));//num表示p/i这个值最大到哪一个
                    ll num=k-i+1;
                    init(d,c,p/i);
                    node mid=qpow(ac,num);
                    anw=init3(mid,anw);
                    i=k+1;
                }
            }

            cout<<anw.a[0][0]<<endl;
        }
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/luowentao/p/9474575.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值