zoukankan      html  css  js  c++  java
  • 【ZOJ】3785 What day is that day? ——浅谈KMP在ACM竞赛中的暴力打表找规律中的应用

    转载请声明出处:http://www.cnblogs.com/kevince/p/3887827.html    ——By Kevince

    首先声明一下,这里的规律指的是循环,即找到最小循环周期。

    这么一说大家心里肯定有数了吧,“不就是next数组性质的应用嘛”,没错,正是如此。

    在ACM的比赛中有些时候会遇到一些题目,可以或必须通过找出数据的规律来编写代码,这里我们专门来讨论下 如何运用KMP中next数组的性质 来寻找一个长数组中的最小循环周期。

    先来看一道题

    ZOJ 3785

    What day is that day?

    Time Limit: 2 Seconds      Memory Limit: 65536 KB

    It's Saturday today, what day is it after 11 + 22 + 33 + ... + NN days?

    Input

    There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

    There is only one line containing one integer N (1 <= N <= 1000000000).

    Output

    For each test case, output one string indicating the day of week.

    Sample Input

    2
    1
    2
    

    Sample Output

    Sunday
    Thursday
    

    Hint

    A week consists of Sunday, Monday, Tuesday, Wednesday, Thursday, Friday and Saturday.

     

    题目的大意是知道今天是周六,让你求 f = 11 + 22 + 33 + ... + NN 这么多天之后是星期几。

    也就是求f % 7对于每个输入的N的值。这题在网上一搜题解,都说是打表找规律,当然这题有两种找法,一是对于每个ii  % 7 的值都找规律。

    这里我们打表可知 前100个值如下所示

    1 4 6 4 3 1 0 1 1 4 2 1 6 0 1 2 5 1 5 1 0 1 4 1 4 4 6 0 1 1 3 2 6 1 0 1 2 2 1 2 6 0 1 4 6 4 3 1 0 1 1 4 2 1 6 0 1 2 5 1 5 1 0 1 4 1 4 4 6 0 1 1 3 2 6 1 0 1 2 2 1 2 6 0 1 4 6 4 3 1 0 1 1 4 2 1 6 0 1 2

    有一种找规律的方法是当有数字等于第一个数的时候做个标记,再人工判断是否能够构成一个循环。

    不可否认的,对于周期较短的一组数字这样找周期并不难,可是如果周期大到数百数千甚至数万时,靠这种方法找周期恐怕是杯水车薪。

    当时我就迷茫在了这一长串的数字中不知所措,猛然想起前不久看过的KMP中next数组的性质,当即想到了用KMP求最小重复子串长度的方法,于是脑洞大开……

    该性质为:令j=leni-next[i],如果i%j==0且i/j>1,j就是Pi的最小循环节( Pi表示文本串的前i个字符,leni表示该字符串的长度,一般表示为leni = i + 1)

    关键代码如下:

    /*注:int next[]为next数组,int arr[]为要找规律的数组,len为数组长度*/
    next[0] = 0;
    for(int i = 1, q = 0; i < len; i++){
        while(q > 0 && arr[i] != arr[q])
            q = next[q-1];
        if (arr[i] == arr[q])
            q++;
        next[i] = q;
        if (q != 0 && (i + 1) % (i + 1 - q) == 0){
            printf("%d
    ", i+1-q);
            break;
        }
    }
    View Code

    可以求出最小周期为42。

     

    还有一种找规律的方法是直接对 f % 7 的值进行打表找规律,按照上述方法找到的周期为294,下面要做的就很简单了~

    AC代码如下:

     1 #include <cstdio>
     2 
     3 const char day[10][10] = {"Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
     4 int s[300];
     5 
     6 int work(int n)
     7 {
     8     int sum = 1;
     9     for(int i = 1; i <= n; i++){
    10         sum = sum * n;
    11         sum %= 7;
    12     }
    13     return sum;
    14 }
    15 
    16 void init()
    17 {
    18     s[0] = 0;
    19     for(int i = 1; i <= 294; i++){
    20         s[i] = s[i-1] + work(i);
    21         s[i] %= 7;
    22     }
    23 }
    24 
    25 int main()
    26 {
    27     int T;
    28     int n;
    29     init();
    30     scanf("%d", &T);
    31     while(T--){
    32         scanf("%d", &n);
    33         n %= 294;
    34         printf("%s
    ", day[ s[n]]);
    35     }
    36     return 0;
    37 }
    View Code

     

    ---------------------------------------------------------我是分割线--------------------------------------------------------------

    自从上次大开脑洞之后,今天又遇到了一道题,POJ 3070。

    题目的大意是让你求第n个斐波那契数的后四位是多少,题目的本意考察的是矩阵快速幂,可是暴力打表又有何不可呢?遂打表用KMP查询,找到周期为15000,顺利水过了这题~

     

    嗯,这篇文章只是跟大家分享一下自己偶然发现的KMP在竞赛中一种用法,在有些题目中使用不免有投机取巧之嫌(就像POJ 3070 ╮(╯▽╰)╭),不过不管投机不投机,只要能AC,就是好方法。O(∩_∩)O哈哈~ 开个玩笑,若有不足之处,还请各位指正。

     

  • 相关阅读:
    Runoob-JSP:JSP 表单处理
    Runoob-JSP:JSP 状态码
    Runoob-JSP:JSP 服务器响应
    extundelete
    Java实现 洛谷 P1601 A+B Problem(高精)
    Java实现 洛谷 P1601 A+B Problem(高精)
    Java实现 洛谷 P1601 A+B Problem(高精)
    Java实现 洛谷 P1508 Likecloud-吃、吃、吃
    Java实现 洛谷 P1508 Likecloud-吃、吃、吃
    Java实现 洛谷 P1508 Likecloud-吃、吃、吃
  • 原文地址:https://www.cnblogs.com/kevince/p/3887827.html
Copyright © 2011-2022 走看看