UVa-11582:Colossal Fibonacci Numbers!(模算术)
这是个开心的题目,因为既可以自己翻译,代码又好写ヾ(๑╹◡╹)ノ"
The i’th Fibonacci number f(i) is recursively defined in the following way:
• f(0) = 0 and f(1) = 1
• f(i + 2) = f(i + 1) + f(i) for every i ≥ 0
Your task is to compute some values of this sequence.
Input
Input begins with an integer t ≤ 10,000, the number of test cases. Each test case consists of three integers a, b, n where 0 ≤ a,b < 264 (a and b will not both be zero) and 1 ≤ n ≤ 1000.
Output
For each test case, output a single line containing the remainder of f(ab) upon division by n.
Sample Input
3
1 1 2
2 3 1000
18446744073709551615 18446744073709551615 1000
Sample Output
1
21
250
概译:对于斐波那契数列f = {0,1,1,2……},给出n,f数列的所有项都%=n,还给了a和b,求f[ab]等于几。
思路:
发现a和b极大所以肯定是找规律了
--> 斐波那契是固定的那循环长度应该跟n有关
--> 余数最多有n种,(注意序列是0,1开头),则最坏情况下n个数以后又爆出0
--> 斐波那契数列只要确定两个数则后面的序列都是确定的,确定了0以后,0后面那个数一旦确定则循环节就确定了
--> 最坏情况,0的后面n次以后爆出1
--> 故在n²个数以内必出循环节,n²的暴力还是可以承受的,找一下循环节长度L,输出f[ab%L(快速幂)]
PS:不妨简单证明一下0的后面最坏n次以后必爆1.
假如序列会发生:01abc,02xyz,02xyz,01……这种情况,则由于非1数字先行重复了,会导致我们未必在n次以内捕获数字1.但这种情况真的会存在吗?
--> 如果真的存在了,由于z+0=2,所以一旦02循环,则02将成为永远的循环节,不会再出现01了,只会有01abc,02xyz,02xyz,02xyz,……
--> (c+0)%n=2,c又在0~n之内,c=2=z
--> (b+c)%n=0,b又在0~n之内,b=n-2=y
--> ……以此类推,01何以创造02帝国?
--> 矛盾。故斐波那契一定是以01开头的循环节,n次内必爆1.
声明:由于紫书和题解们都是一笔描过n²内可求解,故上述想法为个人脑洞,欢迎纠错与讨论。
50ms
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef unsigned long long ull; 5 6 int test, n, f[1000010]={0,1}; 7 ull a, b; 8 9 ull qpow(ull a, ull b, int mod)//为了防爆ull,a传入a%mod 10 { 11 ull ans = 1; 12 while (b) 13 { 14 if (b%2 == 1) ans = ans*a%mod; 15 a = a*a%mod; 16 b >>= 1; 17 } 18 return ans; 19 } 20 21 int main() 22 { 23 scanf("%d", &test); 24 while (test--) 25 { 26 int record = 1; 27 scanf("%llu%llu%d", &a, &b, &n); 28 //寻找循环节 29 //也可以把f开成f[maxn][maxn*maxn+5]在test循环之前预处理 30 //如果预处理的话这里直接O(1)查询了,空间换时间吧 31 for (int i = 2; i <= n*n + 1; i++) 32 { 33 f[i] = (f[i-1] + f[i-2]) % n; 34 if (f[i] == 1 && f[i-1] == 0) 35 { 36 record = i-1;//循环节长度 37 break; 38 } 39 } 40 printf("%d\n", n == 1 ? 0 : f[qpow(a%record, b, record)]); 41 } 42 }
再贴一个预处理的标程:
20ms
1 // UVa11582 Colossal Fibonacci Numbers! 2 3 // Rujia Liu 4 5 #include<iostream> 6 7 #include<cstring> 8 9 #include<cstdio> 10 11 using namespace std; 12 13 14 15 const int maxn = 1000 + 5; 16 17 typedef unsigned long long ULL; 18 19 20 21 int f[maxn][maxn*6], period[maxn]; 22 23 24 25 int pow_mod(ULL a, ULL b, int n) { 26 27 if(!b) return 1; 28 29 int k = pow_mod(a, b/2, n); 30 31 k = k * k % n; 32 33 if(b % 2) k = k * a % n; 34 35 return k; 36 37 } 38 39 40 41 int solve(ULL a, ULL b, int n) { 42 43 if(a == 0 || n == 1) return 0; // attention! 44 45 int p = pow_mod(a % period[n], b, period[n]); 46 47 return f[n][p]; 48 49 } 50 51 52 53 int main() { 54 55 for(int n = 2; n <= 1000; n++) { 56 57 f[n][0] = 0; f[n][1] = 1; 58 59 for(int i = 2; ; i++) { 60 61 f[n][i] = (f[n][i-1] + f[n][i-2]) % n; 62 63 if(f[n][i-1] == 0 && f[n][i] == 1) { 64 65 period[n] = i - 1; 66 67 break; 68 69 } 70 71 } 72 73 } 74 75 ULL a, b; 76 77 int n, T; 78 79 cin >> T; 80 81 while(T--) { 82 83 cin >> a >> b >> n; 84 85 cout << solve(a, b, n) << "\n"; 86 87 } 88 89 return 0; 90 91 }
至于为什么标程的二维f数组只开到maxn*6……我打了个表,最长是n=750时循环节3000~