acdream oj 1124 喵喵的遗憾 (斐波那契数列循环节)
题意:

F0 = 1 , F1 = 1 , F2 = 2 , Fn = Fn-1+Fn-2
求:
FFFn Mod P
( 也就是 F[ F[ F[n] ] ] % P )
思路:原来这是适牛出的题2333.
需要注意的是p可能为1,因此n==0或者1的时候,特判要输出1%p而不是1.
其他的没了。就是求斐波那契数列循环节的经典做法。
1/* ***********************************************
2Author :111qqz
3Created Time :Thu 03 Nov 2016 08:09:26 AM CST
4File Name :1124.cpp
5************************************************ */
6#include <cstdio>
7#include <cstring>
8#include <iostream>
9#include <algorithm>
10#include <vector>
11#include <queue>
12#include <set>
13#include <map>
14#include <string>
15#include <cmath>
16#include <cstdlib>
17#include <ctime>
18#define fst first
19#define sec second
20#define lson l,m,rt<<1
21#define rson m+1,r,rt<<1|1
22#define ms(a,x) memset(a,x,sizeof(a))
23typedef long long LL;
24#define pi pair < int ,int >
25#define MP make_pair
26using namespace std;
27const double eps = 1E-8;
28const int dx4[4]={1,0,0,-1};
29const int dy4[4]={0,-1,1,0};
30const int inf = 0x3f3f3f3f;
31struct Mat
32{
33 LL mat[2][2];
34 void clear()
35 {
36 ms(mat,0);
37 }
38}M,M1;
39Mat mul (Mat a,Mat b,LL mod)
40{
41 Mat c;
42 c.clear();
43 for ( int i = 0 ; i < 2 ; i++)
44 for ( int j = 0 ; j < 2 ; j++)
45 for ( int k = 0 ; k < 2 ; k++)
46 c.mat[i][j] = (c.mat[i][j] + a.mat[i][k] * b.mat[k][j]%mod)%mod;
47 return c;
48}
49Mat mat_ksm(Mat a,LL b,LL mod)
50{
51 Mat res;
52 res.clear();
53 for ( int i = 0 ; i < 2 ; i++) res.mat[i][i] = 1;
54 while (b>0)
55 {
56 if (b&1) res = mul(res,a,mod);
57 b = b >> 1LL;
58 a = mul(a,a,mod);
59 }
60 return res;
61}
62LL gcd(LL a,LL b)
63{
64 return b?gcd(b,a%b):a;
65}
66const int N = 1E6+7;
67bool prime[N];
68int p[N];
69void isprime() //一个普通的筛
70{
71 int cnt = 0 ;
72 ms(prime,true);
73 for ( int i = 2 ; i < N ; i++)
74 {
75 if (prime[i])
76 {
77 p[cnt++] = i ;
78 for ( int j = i+i ; j < N ; j+=i) prime[j] = false;
79 }
80 }
81}
82LL ksm( LL a,LL b,LL mod)
83{
84 LL res = 1;
85 while (b>0)
86 {
87 if (b&1) res = (res * a) % mod;
88 b = b >> 1LL;
89 a = a * a % mod;
90 }
91 return res;
92}
93LL legendre(LL a,LL p) //勒让德符号,判断二次剩余
94{
95 if (ksm(a,(p-1)>>1,p)==1) return 1;
96 return -1;
97}
98LL pri[N],num[N];//分解质因数的底数和指数。
99int cnt; //质因子的个数
100void solve(LL n,LL pri[],LL num[])
101{
102 cnt = 0 ;
103 for ( int i = 0 ; p[i] * p[i] <= n ; i++)
104 {
105 if (n%p[i]==0)
106 {
107 int Num = 0 ;
108 pri[cnt] = p[i];
109 while (n%p[i]==0)
110 {
111 Num++;
112 n/=p[i];
113 }
114 num[cnt] = Num;
115 cnt++;
116 }
117 }
118 if (n>1)
119 {
120 pri[cnt] = n;
121 num[cnt] = 1;
122 cnt++;
123 }
124}
125LL fac[N];
126int cnt2; //n的因子的个数
127void get_fac(LL n)//得到n的所有因子
128{
129 cnt2 = 0 ;
130 for (int i = 1 ; i*i <= n ; i++)
131 {
132 if (n%i==0)
133 {
134 if (i*i!=n)
135 {
136 fac[cnt2++] = i ;
137 fac[cnt2++] = n/i;
138 }
139 else fac[cnt2++] = i;
140 }
141 }
142}
143LL find_loop(LL n)
144{
145 solve(n,pri,num);
146 LL ans = 1;
147 for ( int i = 0 ; i < cnt ; i++)
148 {
149 LL rec = 1;
150 if (pri[i]==2) rec = 3;
151 else if (pri[i]==3) rec = 8;
152 else if (pri[i]==5) rec = 20;
153 else
154 {
155 if (legendre(5,pri[i])==1)
156 get_fac(pri[i]-1);
157 else get_fac(2*pri[i]+2);
158 sort(fac,fac+cnt2);
159 for ( int j = 0 ; j < cnt2 ; j++) //挨个验证因子
160 {
161 Mat tmp = mat_ksm(M,fac[j],pri[i]); //下标从0开始,验证fac[j]为循环节,应该看fib[0]==fib[fac[j]]和fib[1]==fib[fac[j]+1]是否成立
162 tmp = mul(tmp,M1,pri[i]);
163 if (tmp.mat[0][0]==1&&tmp.mat[1][0]==1)
164 {
165 rec = fac[j];
166 break;
167 }
168 }
169 }
170 for ( int j = 1 ; j < num[i] ; j++)
171 rec *=pri[i];
172 ans = ans / gcd(ans,rec) * rec;
173 }
174 return ans;
175}
176void init()
177{
178 M.clear();
179 M.mat[0][1] = M.mat[1][0] = M.mat[1][1] = 1;
180 M1.clear();
181 M1.mat[0][0] = M1.mat[1][0] = 1;
182}
183LL get_fib(LL n,LL mod)
184{
185// cout<<"n:"<<n<<" mod:"<<mod<<endl;
186 if (mod==1) return 0;
187 Mat ret;
188 ret = mat_ksm(M,n-1,mod);
189 ret = mul(ret,M1,mod);
190 return (ret.mat[1][0])%mod;
191}
192LL n,P;
193LL loop[N];
194int main()
195{
196 #ifndef ONLINE_JUDGE
197 freopen("code/in.txt","r",stdin);
198 #endif
199 int T;
200 isprime();
201 init();
202 cin>>T;
203 while (T--)
204 {
205 scanf("%lld%lld",&n,&P);
206 if (n==0||n==1)
207 {
208 printf("%lld\n",1%P);//p可以等于1....
209 continue;
210 }
211 loop[0]=P;
1 LL cur = n ;
2 for (int i = 1; i <= 2 ; i++) loop[i] = find_loop(loop[i-1]);
3 //check
4// for ( int i = 0 ;i <= 2 ; i++) printf("loop:%lld\n",loop[i]);
5 for ( int i = 2 ; i >= 0 ; i--) {
6 cur = get_fib(cur,loop[i]);
7// printf("cur:%lld\n",cur);
8 }
9 printf("%lld\n",cur);
10 }
11 #ifndef ONLINE_JUDGE
12 fclose(stdin);
13 #endif
14 return 0;
15}