Sequence
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1181 Accepted Submission(s): 431
Problem Description
Let us define a sequence as below
Your job is simple, for each task, you should output Fn module 109+7.
Input
The first line has only one integer T, indicates the number of tasks.
Then, for the next T lines, each line consists of 6 integers, A , B, C, D, P, n.
1≤T≤200≤A,B,C,D≤1091≤P,n≤109
Sample Input
2
3 3 2 1 3 5
3 2 2 2 1 4
Sample Output
36
24
题意:
如上图公式所示,让你求出第n项
解析:
首先讲大佬的方法吧,我自己的方法可能有点麻烦.......不过核心思想是一样的——枚举
因为这一项,好像总共只有项,所以我们就可以发现,在一段连续的区间内的的常数项是相等的。
如果是相等的话,我们就可以用一个矩阵求出这一段区间里面的任意一项。
那么对于这一段段连续的常数相等的区间,我们就可以一步步递推下去。
构造两个矩阵这里枚举每一段区间的时候,就让x=这一段区间的常数项的值,
然后再让s1*s2,就可以算出该区间任意的一个值
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MOD = 1e9+7;
const int MAXN = 40000;
typedef struct {
int m[4][4];
int sizx,sizy;
}Matrix;
int n,m;
int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
inline Matrix Mul(Matrix a, Matrix b)
{
Matrix c;
memset(c.m, 0, sizeof(c.m));
c.sizx=a.sizx;
c.sizy=b.sizy;
for (int i = 0; i < a.sizx; i++)
{
for (int j = 0; j < b.sizy; j++)
{
for (int k = 0; k < a.sizy; k++)
{
c.m[i][j] = (c.m[i][j] + (1ll * a.m[i][k] * b.m[k][j])%MOD )%MOD ;
}
}
}
return c;
}
inline Matrix fastm(Matrix a, ll num)
{
Matrix res;
memset(res.m, 0, sizeof(res.m));
res.sizx=a.sizx;
res.sizy=a.sizy;
for(int i=0;i<a.sizx;i++)
res.m[i][i]=1;
while (num)
{
if (num & 1)
res = Mul(res, a);
num >>= 1;
a = Mul(a, a);
}
return res;
}
inline Matrix ReZero()
{
Matrix zero;
zero.m[0][0]=0;
zero.m[0][1]=zero.m[0][2]=0;
zero.m[1][0]=0;
zero.m[1][1]=zero.m[1][2]=0;
zero.m[2][0]=zero.m[2][1]=0;
zero.m[2][2]=0;
zero.sizx=zero.sizy=3;
return zero;
}
int prime[MAXN];
int tot=0;
int main()
{
int t;
//scanf("%d",&t);
t=read();
int A,B,C,D,P;
while(t--)
{
//scanf("%lld%lld%lld%lld%lld%d",&A,&B,&C,&D,&P,&n);
//scanf("%d%d%d%d%d%d",&A,&B,&C,&D,&P,&n);
A=read();
B=read();
C=read();
D=read();
P=read();
n=read();
if(n==1)
{
printf("%d\n",A);
continue;
}
if(n==2)
{
printf("%d\n",B);
continue;
}
int res=0;
Matrix s1;
s1.m[0][0]=A;
s1.m[0][1]=B;
s1.m[0][2]=0;
s1.sizx=1;
s1.sizy=3;
Matrix b;
b.m[0][0]=0;
b.m[0][1]=C;
b.m[0][2]=0;
b.m[1][0]=1;
b.m[1][1]=D;
b.m[1][2]=0;
b.m[2][0]=0;
b.m[2][1]=b.m[2][2]=1;
b.sizx=b.sizy=3;
for(int i=3;i<=n;)
{
int ans=P/i;
if(ans==0)
{
s1.m[0][2]=ans;
Matrix s2=fastm(b,n-i+1);
s1=Mul(s1,s2);
break;
}
int w=P/ans;
w=w>n?n:w;
s1.m[0][2]=ans;
Matrix s2=fastm(b,w-i+1);
s1=Mul(s1,s2);
i=w+1;
}
printf("%d\n",s1.m[0][1]);
}
return 0;
}
下面就是我自己的方法了.......
我是把常数和前面的那项分出来的
Qn是可以用矩阵快速幂算的
后面那项我枚举了几个
我发现了前一项的系数,是由后面两项相乘得到了,即
之后的每一项也可以由这个规律推出
那么我们就可以写出Kn的表达式了
...
这样我们就可以用矩阵快速幂来求Kn了,同样是上面的思想,一段段递推上去,
因为这里有求和,因为这些值我们是求和的,所以构造的矩阵为
sum为X的区间和,即先求出一段区间的系数和,再把他们乘以常数项,就是Kn的一段区间的值
注意这里要一步步递推上去,对于区间[j,w]不能用类似前缀和的思想[w,1]-[j-1,1]来求,会T.....
然后我这里把j==w的情况也单独拿出来算,避免使用快速幂消耗时间...所以常数优化一波后跑了0.7s。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MOD = 1e9+7;
const int MAXN = 40000;
typedef struct {
int m[4][4];
int sizx,sizy;
}Matrix;
int n,m;
int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
inline Matrix Mul(Matrix a, Matrix b)
{
Matrix c;
memset(c.m, 0, sizeof(c.m));
c.sizx=a.sizx;
c.sizy=b.sizy;
for (int i = 0; i < a.sizx; i++)
{
for (int j = 0; j < b.sizy; j++)
{
for (int k = 0; k < a.sizy; k++)
{
c.m[i][j] = (c.m[i][j] + (1ll * a.m[i][k] * b.m[k][j])%MOD )%MOD ;
}
}
}
return c;
}
inline Matrix Del(Matrix a, Matrix b)
{
Matrix c;
//memset(c.m, 0, sizeof(c.m));
c.sizx=a.sizx;
c.sizy=a.sizy;
for (int i = 0; i < a.sizx; i++)
{
for (int j = 0; j < a.sizy; j++)
{
c.m[i][j]=(a.m[i][j]-b.m[i][j]+MOD)%MOD;
}
}
return c;
}
inline Matrix fastm(Matrix a, ll num)
{
Matrix res;
memset(res.m, 0, sizeof(res.m));
res.sizx=a.sizx;
res.sizy=a.sizy;
for(int i=0;i<a.sizx;i++)
res.m[i][i]=1;
while (num)
{
if (num & 1)
res = Mul(res, a);
num >>= 1;
a = Mul(a, a);
}
return res;
}
inline Matrix ReZero()
{
Matrix zero;
zero.m[0][0]=0;
zero.m[0][1]=zero.m[0][2]=0;
zero.m[1][0]=0;
zero.m[1][1]=zero.m[1][2]=0;
zero.m[2][0]=zero.m[2][1]=0;
zero.m[2][2]=0;
zero.sizx=zero.sizy=3;
return zero;
}
int prime[MAXN];
int tot=0;
int main()
{
int t;
//scanf("%d",&t);
t=read();
int A,B,C,D,P;
while(t--)
{
//scanf("%lld%lld%lld%lld%lld%d",&A,&B,&C,&D,&P,&n);
//scanf("%d%d%d%d%d%d",&A,&B,&C,&D,&P,&n);
A=read();
B=read();
C=read();
D=read();
P=read();
n=read();
if(n==1)
{
printf("%d\n",A);
continue;
}
if(n==2)
{
printf("%d\n",B);
continue;
}
Matrix a,b;
a.m[0][0]=0;
a.m[0][1]=C;
a.m[1][0]=1;
a.m[1][1]=D;
a.sizx=a.sizy=2;
Matrix Q;
Q.m[0][0]=A;
Q.m[0][1]=B;
Q.sizx=1;
Q.sizy=2;
a=fastm(a,n-2);
Q=Mul(Q,a); //算Qn
b.m[0][0]=0;
b.m[0][1]=b.m[0][2]=C;
b.m[1][0]=1;
b.m[1][1]=b.m[1][2]=D;
b.m[2][0]=b.m[2][1]=0;
b.m[2][2]=1;
b.sizx=b.sizy=3;
Matrix K; //算Kn
K.m[0][0]=0;
K.m[0][1]=1;
K.m[0][2]=1;
K.sizx=1;
K.sizy=3;
int j=3;
int res=0;
int ans=P;
int ck=0;
tot=0;
while(ans>=1&&j<=n) //找一开始j==w的区间
{
ans=P/j;
if(ans==0) break;
int w=P/ans;
if(j==w)
{
ck=j;
prime[ck]=ans;
}
else
{
break;
}
j=w+1;
}
Matrix tb;
tb.m[0][0]=0;
tb.m[0][1]=C;
tb.m[1][0]=1;
tb.m[1][1]=D;
tb.sizx=tb.sizy=2;
Matrix tK;
tK.m[0][0]=0;
tK.m[0][1]=1;
tK.sizx=1;
tK.sizy=2;
if(ck>=3) //算j==w的区间的和
{
Matrix sc;
Matrix nb=fastm(tb,n-ck);
sc=Mul(tK,nb);
int wan=prime[ck];
res=(res+1ll*sc.m[0][1]*wan%MOD)%MOD;
for(int i=ck-1;i>=3;i--)
{
sc=Mul(sc,tb);
int wan=prime[i];
res=(res+1ll*sc.m[0][1]*wan%MOD)%MOD;
}
}
Matrix s1,s2;
int k=P>=n?n:P;
s1=K;
if(n>P)
{
s2=fastm(b,n-P);
s1=Mul(K,s2);
s1.m[0][2]=s1.m[0][1];
}
while(ans>=1&&k>=j)
{
ans=P/k;
if(ans==0) break;
int w=(P/(ans+1))+1;
if(w<3) w=3;
s2=fastm(b,k-w);
s1=Mul(s1,s2);
res=(res+1ll*s1.m[0][2]*ans%MOD)%MOD;
s1=Mul(s1,b);
s1.m[0][2]=s1.m[0][1];
k=w-1;
}
res=(res+Q.m[0][1])%MOD;
printf("%d\n",res);
}
return 0;
}