• 【ZOJ】3785 What day is that day? ——KMP 暴力打表找规律


    转自:http://www.cnblogs.com/kevince/p/3887827.html

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

    这么一说大家心里肯定有数了吧,“不就是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)

     

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

      1 #include <iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<vector>
      7 #define N 605
      8 #define M 200
      9 #define ll long long
     10 using namespace std;
     11 int i,j;
     12 int T;
     13 int l;
     14 int a[N],sum[N];
     15 char s[N];
     16 int next[N];
     17 int fun(int n)
     18 {
     19     int re = 1;
     20     for(int i=1;i<=n;i++){
     21         re*=n;
     22         re%=7;
     23     }
     24     return re;
     25 }
     26 void ini()
     27 {
     28     a[0]=sum[0]=0;
     29     a[1]=sum[1]=1;
     30     s[0]='0';
     31     s[1]='1';
     32     for(i=2;i<=N-5;i++){
     33         a[i]=fun(i);
     34         sum[i]+=a[i]+sum[i-1];
     35         sum[i]%=7;
     36         s[i]=sum[i]+'0';
     37     }
     38     s[i]='
    ';
     39     //printf("%s
    ",s);
     40    // for(i=1;i<=M;i++){
     41        // printf(" %d %d %d
    ",i,a[i],sum[i]);
     42        // printf(" %d",sum[i]);
     43     //}
     44     return;
     45 }
     46 
     47 void ini2()
     48 {
     49     int  j = -1,  i = 0;
     50     next[0] = -1;
     51     while(i < N-5)
     52     {
     53           if(j == -1 || s[i] == s[j])
     54          {
     55 
     56                     i++;
     57                     j++;
     58                     next[i] = j;
     59          }
     60          else
     61         {
     62                    j = next[j];
     63         }
     64     }
     65 }
     66 
     67 void ini3()
     68 {
     69     for(int i = 589; i <= N-5; ++i)
     70         {
     71             int length = i - next[i]; //循环节的长度
     72             if(i != length && i % length == 0) //如果有多个循环
     73             {
     74                 printf("%d %d
    ", i, i / length);
     75                 break;
     76             }
     77 
     78         }
     79 }
     80 
     81 int main()
     82 {
     83     int x;
     84     int ans;
     85     ini();
     86     //ini2();
     87    // ini3();
     88     //freopen("data.txt","r",stdin);
     89     scanf("%d",&T);
     90     //while(scanf("%d",&n)!=EOF)
     91     while(T--)
     92     {
     93         scanf("%d",&x);
     94         ans=sum[x%294];
     95         if(ans==0) printf("Saturday
    ");
     96         else if(ans==1) printf("Sunday
    ");
     97         else if(ans==2) printf("Monday
    ");
     98         else if(ans==3) printf("Tuesday
    ");
     99         else if(ans==4) printf("Wednesday
    ");
    100         else if(ans==5) printf("Thursday
    ");
    101         else if(ans==6) printf("Friday
    ");
    102     }
    103     return 0;
    104 }

    后来又练了一次,用了map

    4172110 2016-03-15 15:26:39 Accepted 3785 C++ 820 280 njczy2010
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <map>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <cmath>
     7 #include <string>
     8 
     9 using namespace std;
    10 
    11 #define N 1005
    12 #define ll long long
    13 #define mod 7
    14 
    15 int TT;
    16 int n;
    17 int s[N];
    18 int next[N];
    19 map<int,string> mp;
    20 
    21 void get_next()
    22 {
    23     int i,j;
    24     i = 0;
    25     j = -1;
    26     next[0] = -1;
    27     while(i<N)
    28     {
    29         if(j == -1 || s[i] == s[j]){
    30             i++;j++;next[i] = j;
    31         }
    32         else{
    33             j = next[j];
    34         }
    35     }
    36 }
    37 
    38 int quickpow(int x,int n)
    39 {
    40     int re = 1;
    41     while(n)
    42     {
    43         if(n&1){
    44             re = (re * x) % mod;
    45         }
    46         n /= 2;
    47         x = (x * x) % mod;
    48     }
    49     return re;
    50 }
    51 
    52 void fi()
    53 {
    54     int i;
    55     for(i = 2;i < N;i++){
    56         int length = i - next[i]; //循环节的长度
    57         if(i != length && i % length == 0) //如果有多个循环
    58         {
    59             printf("%d %d %d
    ", i, length, i / length);
    60             break;
    61         }
    62     }
    63 }
    64 
    65 void ini()
    66 {
    67     int i;
    68     s[0] = 0;
    69     for(i = 1;i < N;i++){
    70         s[i] = (s[i - 1] + quickpow(i,i) )%mod;
    71     }
    72     mp[0] = "Saturday";
    73     mp[1] = "Sunday";
    74     mp[2] = "Monday";
    75     mp[3] = "Tuesday";
    76     mp[4] = "Wednesday";
    77     mp[5] = "Thursday";
    78     mp[6] = "Friday";
    79     //get_next();
    80     //fi();
    81     //293
    82 }
    83 
    84 int main()
    85 {
    86     //freopen("in.txt","r",stdin);
    87     //freopen("out.txt","w",stdout);
    88     ini();
    89     scanf("%d",&TT);
    90     while(TT--){
    91     //while(scanf("%d",&n)!=EOF){
    92         scanf("%d",&n);
    93         cout << mp[ s[ n%294 ] ] << endl;
    94     }
    95     return 0;
    96 }
  • 相关阅读:
    LeetCode
    LeetCode
    Django ORM 查询
    The Usage of Pymongo
    MongoDB基操
    Django内置auth模块中login_required装饰器用于类视图的优雅方式
    Django Session配置
    Python虚拟环境
    遇见Flask-Script
    Git使用手册
  • 原文地址:https://www.cnblogs.com/njczy2010/p/3930688.html
Copyright © 2020-2023  润新知