1. 程式人生 > >hdu 6395 Sequence 分塊矩陣快速冪

hdu 6395 Sequence 分塊矩陣快速冪

容易知道 p/i (i=3......n); 在某一區間內是相同的,記錄前一個區間的fn-1,fn-2,對本區間進行矩陣快速冪,確定本區間的界限可以用一句話 即   j=(p/i)==0?n:min(n,p/(p/i)),並不需要二分;

AC 程式碼

#include <iostream>
#include <algorithm>
#include <string.h>
#include <iostream>
#include <map>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn=2e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
LL a[5][5],b[5][5],res[4][4];
void mul(LL t[5][5],LL t1[5][5])
{
    memset(res,0,sizeof(res));
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            for (int k=0;k<3;k++)
                res[i][j]=(res[i][j]+t[i][k]*t1[k][j]%mod)%mod;
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            t[i][j]=res[i][j];
}
void quc(LL a[5][5],LL pow)
{
    memset(b,0,sizeof(b));
    for (int i=0;i<3;i++)
        b[i][i]=1;
    LL temp[5][5];
    for (int i=0;i<3;i++)
        for (int j=0;j<3;j++)
            temp[i][j]=a[i][j];
    while (pow)
    {
        if (pow&1)
            mul(b,temp);
        mul(temp,temp);
        pow>>=1;
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    while (t--)
    {
        int A,B,C,D,p,n;
        cin>>A>>B>>C>>D>>p>>n;
        memset(a,0,sizeof(a));
        a[0][0]=D;a[0][1]=C;a[0][2]=1;
        a[1][0]=1;a[2][2]=1;
        LL f_one,f_sec,fi=B%mod,fj=A%mod;
        for (int i=3;i<=n;)
        {
            LL j=(p/i)==0?n:min(n,p/(p/i));
            LL v=p/i;
            quc(a,j-i+1);
            f_one=((fi*b[0][0]%mod+fj*b[0][1]%mod)%mod+v*b[0][2]%mod)%mod;
            f_sec=((fi*b[1][0]%mod+fj*b[1][1]%mod)%mod+v*b[1][2]%mod)%mod;
            fi=f_one;
            fj=f_sec;
            i=j+1;
        }
        cout<<fi<<endl;
    }
    return 0;
}