UVa-11582:Colossal Fibonacci Numbers!(模算术)

Posted alphawa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa-11582:Colossal Fibonacci Numbers!(模算术)相关的知识,希望对你有一定的参考价值。

这是个开心的题目,因为既可以自己翻译,代码又好写ヾ(????)?"

 

The i’th Fibonacci number f(i) is recursively de?ned 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

--> 故在n2个数以内必出循环节,n2的暴力还是可以承受的,找一下循环节长度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.

 

声明:由于紫书和题解们都是一笔描过n2内可求解,故上述想法为个人脑洞,欢迎纠错与讨论。

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 == 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) << "
";
86 
87   }
88 
89   return 0;
90 
91 }

 

至于为什么标程的二维f数组只开到maxn*6……我打了个表,最长是n=750时循环节3000~

以上是关于UVa-11582:Colossal Fibonacci Numbers!(模算术)的主要内容,如果未能解决你的问题,请参考以下文章

UVA - 11582 Colossal Fibonacci Numbers!循环节

Colossal Fibonacci Numbers! UVA - 11582

uva11582 Colossal Fibonacci Numbers!

UVA11582 Colossal Fibonacci Numbers!

UVa 11582 Colossal Fibonacci Numbers! 大数幂取模

UVA 11582 Colossal Fibonacci Numbers!(循环节打表+幂取模)