题目:Sequence
题意:已知一个递推式,求递推式第n项。
思路:在表达式中,如果 为一个固定常数E,那么这个表达式就可以用矩阵快速幂进行求解。
矩阵构造为: * (
)^num
因此,枚举E的值即可(O(sqrt(P))),每次枚举到的 i 都是的值第一次出现的位置,二分找到其最后一次出现的位置j,在这段区间内E就是一个常数,使用上述矩阵快速幂即可。总时间复杂度:O(sqrt(P)*logn)。
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX = 1e5+10;
const ll mod=1e9+7;
ll a,b,c,d,p;
int n;
typedef struct {
ll m[3][3];
}Matrix;
Matrix Mul(Matrix a, Matrix b)
{
Matrix c;
memset(c.m, 0, sizeof(c.m));
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] += ((a.m[i][k] * b.m[k][j]) % mod + mod) % mod;
c.m[i][j]%=mod;
}
}
}
return c;
}
Matrix fastm(Matrix a, ll num)
{
Matrix res;
memset(res.m, 0, sizeof(res.m));
for(int i=0;i<3;i++)
res.m[i][i] = 1;
while (num)
{
if (num & 1)
res = Mul(res, a);
num >>= 1;
a = Mul(a, a);
}
return res;
}
//二分查找P/i值相同的最大i
ll bin_search(ll i)
{
ll l=i,r=n;
ll current=p/i;
while(l<r){
ll mid=r-((r-l)>>1);
ll tmp=p/mid;
if(tmp==current)
l=mid;
else if(tmp<current)
r=mid-1;
else
l=mid+1;
}
return l;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld%lld%lld%d",&a,&b,&c,&d,&p,&n);
if(n==1){
printf("%lld\n",a);
continue;
}
if(n==2){
printf("%lld\n",b);
continue;
}
ll f1,f2;
f1=a%mod; f2=b%mod;
Matrix y;
y.m[0][0]=0; y.m[0][1]=c; y.m[0][2]=0;
y.m[1][0]=1; y.m[1][1]=d; y.m[1][2]=0;
y.m[2][0]=0; y.m[2][1]=1; y.m[2][2]=1;
for(int i=3;i<=n;i++){
int j=bin_search(i);
ll E=p/i;
//num为E值相同的项数
ll num=j-i+1;
Matrix tmp;
tmp=fastm(y,num);
ll res;
res=(f1*tmp.m[0][0]%mod+f2*tmp.m[1][0]%mod+E*tmp.m[2][0])%mod;
f2=(f1*tmp.m[0][1]%mod+f2*tmp.m[1][1]%mod+E*tmp.m[2][1])%mod;
f1=res;
i=j;
}
printf("%lld\n",f2);
}
}