• 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 == 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~

  • 相关阅读:
    在VMWare中增加Linux文件系统空间
    linux shell 字符串操作(长度,查找,替换)详解
    linux chmod命令参数及用法详解文件文件夹权限设定命令
    Linux分割日志计划任务(原创)
    写日志C#程序
    2011年底,数家大型网站数据库被窃取分析报告(原创)
    ThinkPad SL400全驱动
    东辰信竞学子——从今天开始重新出发!
    CentOS7下安装mysql8027
    arcgis基础
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/9631790.html
Copyright © 2020-2023  润新知