题目:http://acm.hdu.edu.cn/showproblem.php?pid=3411
是一个等比数列,这个已经忘干净了,转:http://blog.csdn.net/wust_xhj/article/details/47779539
其实最好的方法还是猜:
q=2:1,1,3,5,11,21,43,85,171……,很容易看出f[n] = f[n-1] + 2*f[n-2]。
q=3:1,2,7,20,61,182,547,1640……,类比上面有f[n] = 2*f[n-1] + 3*f[n-2]。
猜一下:f[n] = (q-1)*f[n-1] + q*f[n-2],代入原式验证正确。
以下转载证明过程:
学会推导代码就简单了。
也不简单,
主要是递推公式的n-1次方为2^y2 - 1 + Z2,y2,z2就很大,n更大了,但其实不需要算出来。
看代码就知道,做n-1次方时看二进制有几个1就行,2^y2-1正好有y2个1,做y2次运算,再乘上a^z2即可。
f(0)=0,f(1)=1;
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn=2;
ll mod;
struct matrix{
ll arr[maxn][maxn];
matrix operator*(matrix b){
matrix ans;
ll tmp;
for(int i=0; i<maxn; i++)
for(int j=0; j<maxn; j++){
ans.arr[i][j] = 0;
for(int k=0; k<maxn; k++){
tmp = (arr[i][k]*b.arr[k][j])%mod;
ans.arr[i][j] = (ans.arr[i][j] + tmp)%mod;
}
}
return ans;
}
};
matrix quick_pow(matrix a,ll N){
matrix ans;
memset(ans.arr,0,sizeof(ans.arr));
for(int i=0; i<maxn; i++)
ans.arr[i][i] = 1;
while(N){
if(N&1)
ans = ans*a;
a = a*a;
N /= 2;;
}
return ans;
}
ll pow(ll x, ll n){ //快速幂
ll ans=1;
while(n){
if(n&1){
ans=ans*x%mod;
}
x=x*x%mod;
n>>=1;
}
return (ans+mod)%mod;
}
int main(){
ll x1,y1,z1;
matrix a,ans;
while(~scanf("%lld%lld%lld",&x1,&y1,&z1)){
if(x1==-1&&y1==-1&&z1==-1) break;
memset(ans.arr,0,sizeof(ans.arr));
ll y2,z2;
scanf("%lld%lld%lld",&y2,&z2,&mod);
ll q=(pow(x1,y1)+z1)%mod; //求q
ll b[2][2]={(q-1+mod)%mod,q,1,0};
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
a.arr[i][j]=b[i][j];
matrix aa=quick_pow(a,z2);
for(int i=0; i<2; i++) //单位矩阵
ans.arr[i][i] = 1;
for(int i=0;i<y2;i++){ //模仿quick_pow
ans=ans*a;
a=a*a;
}
ans=ans*aa;
ll anss;
anss=(ans.arr[0][0]+mod)%mod;
printf("%lld\n",anss);
}
return 0;
}