当前位置: 代码迷 >> 综合 >> 【HDU - 5451】Best Solver(矩阵快速幂+广义斐波拉契)
  详细解决方案

【HDU - 5451】Best Solver(矩阵快速幂+广义斐波拉契)

热度:43   发布时间:2023-12-06 19:36:28.0

The so-called best problem solver can easily solve this problem, with his/her childhood sweetheart. 

It is known that y=(5+2√6)^(1+2^x). 
For a given integer x (0≤x<2^32) and a given prime number M (M≤46337), print [y]%M. ([y] means the integer part of y) 

Input

An integer T (1<T≤1000), indicating there are T test cases. 
Following are TT lines, each containing two integers xx and MM, as introduced above.

Output

The output contains exactly TT lines. 
Each line contains an integer representing [y]%M[y]%M.

Sample Input

7
0 46337
1 46337
3 46337
1 46337
21 46337
321 46337
4321 46337

Sample Output

Case #1: 97
Case #2: 969
Case #3: 16537
Case #4: 969
Case #5: 40453
Case #6: 10211
Case #7: 17947

 

思路:(参考博客)

如这种a+bsqrt(c)的n次方的,一般最后结果形式还是a+bsqrt(c),所以可以构造出矩阵使用矩阵快速幂,不过这个矩阵的乘方是2^n,n=1e9,所以这里想到了找循环节,广义斐波那契数列的循环节是(MOD-1)*(MOD+1),因此可以用这个来减小指数。不过这里要求是向下取整然后再取模,取模和取整是不满足交换的,因此这里需要消除根号的影响,这里就可以考虑5-2sqrt(6),这个数是一个小于1的数其n次方也一定小于1,5+2sqrt(6)的n次方,可以写成a+b*sqrt(c)+(a-b*sqrt(c))-(a-b*sqrt(c))=2*a-(a-b*sqrt(c)),对上面这个式子向下取整,(a-b*sqrt(c))这个是个小于1的数,2*a是个整数,因此向下取整可以后可以写成2*a-1。然后对其取模就可以。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cctype>
#include<map>
using namespace std;
typedef long long ll;
int M;
struct node{ll m[2][2];void clear(){memset(m,0,sizeof(m));}void one(){memset(m,0,sizeof(m));m[0][0]=1;m[1][1]=1;}
};
struct nod{ll a, b, c, d;
};
node mul(node a,node b){node t;t.clear();for(int i=0;i<2;i++){for(int j=0;j<2;j++){for(int k=0;k<2;k++){t.m[i][j]+=a.m[i][k]*b.m[k][j];t.m[i][j]%=M; }}}return t;
}
node ksm(node a,ll b){node t;t.one();while(b){if(b&1){t=mul(t,a); } a=mul(a,a);b>>=1;}return t; 
}
map<string,int> mp;
map<int,string> mp1;
int isprime(int x){int t=sqrt(x);for(int i=2;i<=t;i++){if(x%i==0)return 0;}return 1;
}ll Euler(ll n)
{ll ret=n; for(ll i=2;i*i<=n;i++)if(n%i==0){ret=ret/i*(i-1);while(n%i==0)n/=i;}if(n>1)ret=ret/n*(n-1);return ret;
}
ll qsm(ll a,ll b,ll p){ll t=1;while(b){if(b&1){t=(t*a)%p;} a=(a*a)%p;b>>=1;}return t;
}
void add(string &ss,ll a,ll len){if(len==0) return ; add(ss,a/10,len-1);ss+='0'+(a%10);
}
int len(ll x){ll t=10,i=1;while(x>=t){t*=10;i++;}return i;
}
int main()
{int t;scanf("%d",&t);int cas=1;while(t--){mp.clear();mp1.clear();ll x;scanf("%lld%d",&x,&M);node a,b;a.one();b.clear();b.m[0][0]=5;b.m[0][1]=12;b.m[1][0]=2;b.m[1][1]=5;a=ksm(b,qsm(2,x,(M-1)*(M+1)));ll res=5*a.m[0][0]+2*a.m[0][1];printf("Case #%d: %lld\n",cas++,(2*res-1)%M);}return 0;
}