7 0 46337 1 46337 3 46337 1 46337 21 46337 321 46337 4321 46337
Case #1: 97 Case #2: 969 Case #3: 16537 Case #4: 969 Case #5: 40453 Case #6: 10211 Case #7: 17947
本题正解是:快速矩阵乘法+ Fibonacci数列的循环节
以下是队里某同学的方法:
首先(5+2sqrt(6))^n + (5-2sqrt(6))^n 是一个整数,且(5-2sqrt(6))^n < 1
所以 (5+2sqrt(6))^n + (5-2sqrt(6))^n = x + y sqrt(6) + x - ysqrt(6)
所以算出 (5+2sqrt(6))^n的整数部分x,答案就是2*x-1
中间过程可以用取模操作。
他的思路是:1+2^x ,把1提出来,最后乘上即可。
对于{(5+2sqrt(6))^(2^n)}^2 = (5+2sqrt(6))^(2^(n+1))
这个乘法是有循环结的。
可能循环节开始位置不是(5+2sqrt(6))所以,预处理即可。
找到循环节以后,取模,然后快速矩阵乘即可。看代码。
#include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<cstdio> using namespace std; #define ll unsigned int struct Node{ int a,b,t; Node(){} Node(int _a,int _t){ a = _a; t = _t; } }; vector<Node> head[50000]; ll mod ; struct Mat{ ll a[2][2]; Mat(){ memset(a,0,sizeof(a)); } Mat operator *(const Mat & b){ Mat c; memset(c.a,0,sizeof(c.a)); for(int i = 0;i < 2; i++) for(int j = 0;j < 2; j++) for(int k = 0;k < 2; k++) c.a[i][j] = (c.a[i][j]+a[i][k]*b.a[k][j])%mod; return c; } }; int main(){ ll t,n,m,tt=1; scanf("%lld",&t); while(t--){ scanf("%lld%lld",&n,&m); mod = m; for(int i = 0;i < m; i++) head[i].clear(); Node a,b; Mat x,y; ll cnt = 1,be=0; x.a[0][0] = x.a[1][1] = 5%mod; x.a[0][1] = 12%mod; x.a[1][0] = 2%mod; y = x; for(;;cnt++){ a.a = x.a[1][0]; a.b = x.a[0][0]; a.t = cnt; int flag = 1; for(int i = 0;i < head[a.b].size(); i++){ if(head[a.b][i].a == a.a){ flag = 0; be = head[a.b][i].t; } } if(flag==0) break; head[a.b].push_back(a); x = x*x; } cnt = cnt - be; ll num = 0,ans; x = y; for(int i = 0;i < min(be,n); i++){ x = x*x; } if(n > be){ n -= be; cnt = n%cnt; for(int i = 0;i < cnt; i++) x = x*x; } x = y * x; ans = 2*x.a[0][0]-1; ans %= mod; printf("Case #%lld: %lld\n",tt++,ans); } return 0; }
出题人的解法:(过后更新)