http://acm.hdu.edu.cn/showproblem.php?pid=5895
题意: F[ x ]=F[ x-1 ] * 2 + F[ x-2 ] G[ x ]=∑F[ i ]
问 x^G[ n*Y ] % (s+1)
思路:之前BC有过类似的题目,这个题目看完了很后悔。。本来是应该可以A掉的。。
思路就是利用欧拉定理来让G变小先。。然后快速幂搞一下。。。
类似斐波那契数列一样。。打表试一试就发现 G[ N ] = F[n]*F[n+1]/2 (证明和斐波那契那个证明方法差不多,两遍同时×F[ n-1 ]),移项累加就好。
所以就很愉快了,但是注意!!!
这里明显除以2是要求一下逆元的!但是逆元显然不一定存在,所以利用求任意逆元的方法,a/b mod c = a mod(b*c)/b
( 最后时间紧张加上基础不牢靠并没有想起来。。十分遗憾 。。。)
代码:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef vector<vector<long long> > mat;
long long M ;
long long M2 ;
mat mul(const mat &A,const mat &B){
mat C(A.size(),vector<long long>(B[0].size()));
for(int i = 0; i < A.size(); i++)
for(int k = 0; k < B.size(); k++)
for(int j = 0; j < B[0].size(); j++){
C[i][j] = (C[i][j] + (A[i][k] * B[k][j])%M) % M;
}
return C;
}
mat pow(mat A, long long n){
mat B(A.size(), vector<long long>(A.size()));
for(int i = 0; i < A.size(); i++){
B[i][i] = 1;
}
while(n>0){
if(n & 1) B =mul(B,A);
A = mul(A,A);
n >>= 1;
}
return B;
}
long long Qpow(long long a,long long n){
long long ans = 1;
while(n){
if(n&1) ans = (ans*a)%M2;
a = (a*a)%M2;
n >>= 1;
}
return ans;
}
long long E(long long n) {
long long ans = n;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
ans -= ans / i;
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) {
ans -= ans / n;
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
vector<long long> v1,v2,v3,v4;
v1.push_back(2);v1.push_back(1);
v2.push_back(1);v2.push_back(0);
v3.push_back(1);
v4.push_back(0);
mat A,B;
A.push_back(v1);A.push_back(v2);
B.push_back(v3);B.push_back(v4);
while(t--){
int n,y,x,s;
scanf("%d%d%d%d",&n,&y,&x,&s);
long long Mi=(long long)n*y;
if(Mi<=11){
long long a=0,b=1;
long long sum=0;
for(int i=1;i<=Mi;i++){
long long c=b;
b=c*2+a;
a=c;
sum+=a*a;
}
M2=s+1;
cout<<Qpow(x,sum)%M2<<endl;
}
else{
M=E(s+1)*2;
mat C=pow(A,Mi);
mat D=mul(C,B);
long long Fin=(D[0][0]*D[1][0])%M/2+M/2;
M2=s+1;
cout<<Qpow(x,Fin)%M2<<endl;
}
}
}