1. 程式人生 > >HDU 6395 Sequence(數論+矩陣快速冪)

HDU 6395 Sequence(數論+矩陣快速冪)

Description

定義序列F1=A,F2=B,Fn=CFn2+DFn1+Pn,求Fn

Input

第一行一整數T表示用例組數,每組用例輸入六個整數A,B,C,D,P,n

(1T20,0A,B,C,D109,1P,n109)

Output

輸出Fn,結果模109+7

Sample Input

2
3 3 2 1 3 5
3 2 2 2 1 4

Sample Output

36
24

Solution

由於Pn只有O(P)種不同取值,得到每種取值對應的n所處區間分別用矩陣快速冪加速求解即可

Code

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define mod 1000000007
int mul(int x,int y)
{
    ll z=1ll*x*y;
    return z-z/mod*mod;
}
int add(int
x,int y) { x+=y; if(x>=mod)x-=mod; return x; } typedef int M[3][3]; void Mul(M &A,M B) { M C; for(int i=0;i<3;i++) for(int j=0;j<3;j++) { C[i][j]=0; for(int k=0;k<3;k++) C[i][j]=add(C[i][j],mul(A[i][k],B[k][j])); } for
(int i=0;i<3;i++) for(int j=0;j<3;j++) A[i][j]=C[i][j]; } void Pow(M &A,int k) { M B; for(int i=0;i<3;i++) for(int j=0;j<3;j++) B[i][j]=(i==j?1:0); while(k) { if(k&1)Mul(B,A); Mul(A,A); k>>=1; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) A[i][j]=B[i][j]; } vector<P>v; int main() { int T,a,b,c,d,p,n; scanf("%d",&T); while(T--) { scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&p,&n); int f1=a,f2=b; v.clear(); for(int i=1,pre=-1;i<=p;i=pre+1) { pre=p/(p/i); pre=min(pre,n); v.push_back(P(i,pre)); if(pre==n)break; } if(p<n)v.push_back(P(p+1,n)); int pre=2;//f[pre],f[pre-1] for(int i=1;i<v.size();i++) { M A; A[0][0]=d,A[0][1]=c,A[0][2]=p/v[i].first; A[1][0]=1,A[1][1]=0,A[1][2]=0; A[2][0]=0,A[2][1]=0,A[2][2]=1; Pow(A,v[i].second-pre); int g2=add(add(mul(A[0][0],f2),mul(A[0][1],f1)),A[0][2]); int g1=add(add(mul(A[1][0],f2),mul(A[1][1],f1)),A[1][2]); f2=g2,f1=g1,pre=v[i].second; } printf("%d\n",f2); } return 0; }