hdu 6395(矩阵快速幂)

发现公式里Ax+By+C里面的c是变化的,所以不能直接快速幂,但打个表发现当p/n向下取整的数一定时,n时分段的,即可以将C相同的分段,分段矩阵快速幂

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
typedef __int64 ll;
ll a,b,c,d,p,n;
const int maxn=1e5+100;
const ll mod=1e9+7;
const int nn=3;
ll f[maxn];
struct maxt
{
    ll m[5][5];
};
maxt mutil(maxt A,maxt B)
{
    maxt temp;
    memset(temp.m,0,sizeof(temp.m));
    for(int i=1; i<=nn; i++)
    {
        for(int j=1; j<=nn; j++)
        {
            for(int k=1; k<=nn; k++)
            {
                temp.m[i][j]=(temp.m[i][j]+A.m[i][k]*B.m[k][j]%mod)%mod;
            }
        }
    }
    return temp;
}
maxt quick_mod(maxt a,int b)
{
    maxt r;
    memset(r.m,0,sizeof(r.m));
    for(int i=1; i<=nn; i++)
        r.m[i][i]=1;
    while(b)
    {
        if(b&1) r=mutil(r,a);
        a=mutil(a,a);
        b=b>>1;
    }

    return r;
}
int ct;
int main()
{
    maxt t;
    scanf("%d",&ct);
    while(ct--)
    {
        scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&p,&n);
////////////////////////////////////////////////////////////////////
        t.m[1][1]=d;
        t.m[1][2]=c;
        t.m[1][3]=1;
        t.m[2][1]=1;
        t.m[2][2]=0;
        t.m[2][3]=0;
        t.m[3][1]=0;
        t.m[3][2]=0;
        t.m[3][3]=1;
/////////////////////////////////////////////////////////////////////
        f[1]=a;
        f[2]=b;
        if(p<9)//因为f要从3开始,所以p小于9的要特殊处理
        {
            if(n<3)
            {
                printf("%I64d\n",f[n]);
                continue;
            }
            ll mm=max((ll)3,p);//防止p小于3
            for(ll i=3; i<=mm; i++)//前p个直接暴力
            {
                f[i]=(c*f[i-2]%mod+d*f[i-1]%mod+(ll)floor(p/i))%mod;
            }
            if(n<=mm)//n小于p的话已经求出,直接输出
            {
                printf("%I64d\n",f[n]);
                continue;
            }
            ll f1=f[mm];
            ll f2=f[mm-1];
            int b=n-mm;
            if(b>0)//否则对n到p之间的数直接快速幂,因为p/n向下取整都为0,Ax+By+C里面的C是不变的,可以直接快速幂
            {
                ll c=0;
                maxt tt=quick_mod(t,b);
                ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod;
                ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod;
                f1=ff1;
                f2=ff2;
            }
            printf("%I64d\n",f1);
        }
        else//p是大于9的
        {
            ll mm=sqrt(p);
            for(ll i=3; i<=mm; i++)//对于小于根号p的数直接暴力
            {
                f[i]=(c*f[i-2]%mod+d*f[i-1]%mod+(ll)floor(p/i))%mod;
            }
            if(n<=mm)
            {
                printf("%I64d\n",f[n]);
                continue;
            }
            ll f1=f[mm];
            ll f2=f[mm-1];
            for(ll i=sqrt(p)-1; i>=1; i--)//根号p到p的数分段快速幂,因为在每段里的Ax+By+C里面的C是不变的,可以直接快速幂
            {
                int r=p/i;
                int l=p/(i+1);
                ll c=i;
                maxt ff;
                if(n>=l&&n<=r)//n在段里,可以直接输出
                {
                    int b=n-l;
                    maxt tt=quick_mod(t,b);
                    ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod;
                    ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod;
                    f1=ff1;
                    f2=ff2;
                    break;
                }
                int b=r-l;
                maxt tt=quick_mod(t,b);
                ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod;
                ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod;
                f1=ff1;
                f2=ff2;
            }
            int b=n-p;//n是大于p的,则对n到p之间的数直接快速幂
            if(b>0)
            {
                ll c=0;
                maxt tt=quick_mod(t,b);
                ll ff1=(tt.m[1][1]*f1%mod+tt.m[1][2]*f2%mod+tt.m[1][3]*c%mod)%mod;
                ll ff2=(tt.m[2][1]*f1%mod+tt.m[2][2]*f2%mod+tt.m[2][3]*c%mod)%mod;
                f1=ff1;
                f2=ff2;
            }
            printf("%I64d\n",f1);
        }

    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Wangwanxiang/p/9480594.html
今日推荐