http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1010&cid=808
题意:在扩展斐波纳挈的基础上加了一个变量 P/n P / n 。求第 n n 项的取值。
分析:考虑将每一种进行矩阵快速幂,也就是进行了整数分块处理。对于每一个整数块可以使用矩阵快速幂,然后维护 A,B A , B 用作下一次的矩阵快速幂使用。
整数分块:
通过二分来求分块可以解决这个问题。
也可以用更为高效的
On√
O
n
效率来解决,类似于线性筛。
写法参考如下:
http://www.cnblogs.com/peng-ym/p/8661118.html
矩阵构造如下:
C、D
C
、
D
如题意所示。
E
E
为常数,即原式中的。
两矩阵相乘后的结果:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#define LL long long
using namespace std;
const LL N = 100000+33;
const LL M = 200000+33;
const LL inf = 0x3f3f3f3f;
const LL mod = 1e9+7;
LL a,b,c,d,p;
struct node
{
LL a[4][4];
void init(){
memset(a,0,sizeof a);
}
node friend operator * (node a,node b)
{
node c;
c.init();
for(LL i=1;i<=3;i++){
for(LL j=1;j<=3;j++){
for(LL k=1;k<=3;k++){
c.a[i][j]+=a.a[i][k]*b.a[k][j];
c.a[i][j]%=mod;
}
}
}
return c;
}
};
LL A,B;
LL fff(LL mi,LL k)
{
node x;
x.a[1][1]=d;x.a[1][2]=c;x.a[1][3]=1;
x.a[2][1]=1;x.a[2][2]=0;x.a[2][3]=0;
x.a[3][1]=0;x.a[3][2]=0;x.a[3][3]=1;
node ans;
ans.a[1][1]=1;ans.a[1][2]=0;ans.a[1][3]=0;
ans.a[2][1]=0;ans.a[2][2]=1;ans.a[2][3]=0;
ans.a[3][1]=0;ans.a[3][2]=0;ans.a[3][3]=1;
while(mi){
if(mi&1)
ans=ans*x;
x=x*x;
mi>>=1;
}
LL A1=A,B1=B;
B=ans.a[1][1]*B1%mod+ans.a[1][2]*A1%mod+ans.a[1][3]*k%mod;
B%=mod;
A=ans.a[2][1]*B1%mod+ans.a[2][2]*A1%mod+ans.a[2][3]*k%mod;
A%=mod;
return B;
}
LL val[100000];//所有块P/n的值,常数E
LL num[100000];//每块的数量
LL cs;
void init(LL n)
{
cs=0;
for(LL l=1,r;l<=n;l=r+1)//sqrt(n)效率
{
r=n/(n/l);
val[++cs]=r;
}
LL res=0;
for(LL i=cs;i>=1;i--){
num[i]=n/val[i]-res;
res+=num[i];
}
num[cs]--;
num[cs-1]--;
for(LL i=1;i<=cs;i++){
// prLLf("%lld %lld \n",val[i],num[i]);
}
}
int main()
{
LL T;
scanf("%lld",&T);
while(T--){
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&p);
A=a,B=b;
LL n;
scanf("%lld",&n);
LL ans=0;
init(p);
if(n>=3){
LL aim=2;
LL now = p/3;
LL pos=0;
for(int i=1;i<=cs;i++) if(val[i]==now){
pos=i;
break;
}
while(aim<n&&pos>0){
if(aim+num[pos]<=n){
aim=aim+num[pos];
fff(num[pos],val[pos]);
}else{
fff(n-aim,val[pos]);
aim=n;
}
pos--;
}
if(aim<n){
fff(n-aim,0);
}
ans=B;
printf("%lld\n",ans);
}else{
if(n==2)
printf("%lld\n",B);
else
printf("%lld\n",A);
}
}
return 0;
}