2018 Multi-University Training Contest 7 HDU 6396Sequence

Bryce1010模板

https://vjudge.net/problem/HDU-6395

题意:
求题中类似斐波那契数列的公式的值。

思路:
如果还记得斐波那契数列的矩阵解法的话,应该会很容易就先到矩阵快速幂吧。。。可他喵我忘了。

如果想复习一遍可以看这个博客:https://blog.csdn.net/flyfish1986/article/details/48014523
大体就是对于一个斐波那契数列,如果系数都是常数(包括常数项),就可以分解成矩阵相乘的形式,可以发现,常数项 P/i P / i 可以分成 sqrt(n) s q r t ( n ) 块常数项。优化的话,可以用二分来找每个块的边界值。

#include<bits/stdc++.h>

using namespace std;
const int MAXN=5e5+10;
const int INF=0x3f3f3f3f;
const int Mod=1e9+7;
#define ll long long


//构造矩阵及矩阵乘法
struct Matrix
{
    ll m[3][3];
    Matrix(){memset(m,0,sizeof(m));}
    Matrix operator * (Matrix &b)
    {
        Matrix c;
        for(int i=0;i<3;i++)
        {
            for(int j=0;j<3;j++)
            {
                for(int k=0;k<3;k++)
                {
                    c.m[i][j]=(c.m[i][j]+m[i][k]*b.m[k][j]);
                }
                c.m[i][j]%=Mod;

            }
        }
        return c;
    }
}I;


//矩阵快速幂
Matrix pow_mod(Matrix a,int b)
{
    Matrix c=I;
    while(b)
    {
        if(b&1)c=c*a;
        a=a*a;
        b>>=1;
    }
    return c;
}

ll A,B,C,D,P,n,t;
ll BiFind(ll i)
{
    ll key=P/i;
    ll l=i,r=n;
    while(l<r)
    {
        int mid=r-(r-l)/2;
        if(P/mid==key)l=mid;
        else if(P/mid<key)r=mid-1;
        else l=mid+1;
    }
    return l;

}
int main()
{

    I.m[0][0]=I.m[1][1]=I.m[2][2]=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld%lld%lld%lld",&A,&B,&C,&D,&P,&n);
        if(n==1)
        {
            printf("%lld\n",A);
            continue;
        }
        if(n==2)
        {
            printf("%lld\n",B);
            continue;
        }
        Matrix M;
        //存储计算矩阵
        M.m[0][0]=D;M.m[0][1]=C;M.m[0][2]=1;
        M.m[1][0]=1;M.m[1][1]=0;M.m[1][2]=0;
        M.m[2][0]=0;M.m[2][1]=0;M.m[2][2]=1;
        ll f1=B,f2=A;
        for(int i=3;i<=n;)
        {
            ll j=BiFind(i);
            ll f3=P/i;
            Matrix ans=pow_mod(M,j-i+1);

            ll _f1=(f1*ans.m[0][0]%Mod+f2*ans.m[0][1]%Mod+f3*ans.m[0][2]%Mod)%Mod;
            ll _f2=(f1*ans.m[1][0]%Mod+f2*ans.m[1][1]%Mod+f3*ans.m[1][2]%Mod)%Mod;
            ll _f3=(f1*ans.m[2][0]%Mod+f2*ans.m[2][1]%Mod+f3*ans.m[2][2]%Mod)%Mod;
            f1=_f1;
            f2=_f2;
            f3=_f3;
            i=j+1;

        }
        cout<<f1<<endl;
    }

    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值