zoukankan      html  css  js  c++  java
  • [POI2012]OKR-A Horrible Poem hash

    题面: 洛谷

    题解:

      首先我们需要知道一个性质,串s的最小循环节 = len - next[len].其中next[len]表示串s的一个最长长度使得s[1] ~ s[next[len]] == s[len - next[len] + 1] ~ s[len](详细定义参见KMP)

      至于为什么是成立的可以画图推一下,这个应该是比较常见的性质。

      

      可能画的有点丑。。。

      图中每个绿色方块所代表的串都是相同的,因为第一个绿块显然与下面那块相同,而根据next的定义,它也与第二行第二个绿块相同……以此类推,可以一直递推下去,直到推完整个数组。

      

      对于一个长度为len的串s而言,设它的最小循环节长度为l.

      若$len = p_{1}^{k_{1}} cdot p_{2}^{k_{2}} cdot p_{3}^{k_{3}}...p_{t}^{k_{t}}$

      则$len = p_{1}^{a_{1}} cdot p_{2}^{a_{2}} cdot p_{3}^{a_{3}}...p_{t}^{a_{t}}$其中$a_{i} le k_{i}$.

      首先一个串的最大循环节长度肯定= len;

      而这个循环节之所以可以变小,是因为这个最大循环节是由很多个最短循环节组成。我们假设最短循环节为X,这这个串可以表示为XXXXXXX(若干个X)

      假设X有b个。那么我们可以每次对b缩减一个b的因子,最后使得b变为1,即使b不断除一个数。

      例如一个串s一开始可以被表示为XXXXXXXX(8个X),即b = 8

      这个时候我们枚举到一个2,于是我们判断原串是否可以被XXXX + XXXX凑出,如果可以,那么b /= 2.

      然后我们判断原串是否可以被XX + XX + XX + XX凑出,如果可以,那么b /= 2.

      依次类推,直到已经没有更小的循环节可以凑出原串位置。

      其中2是b的某个质因子。

      因为b的最大值为len(即循环节为1),所以我们一开始先从len开始,不断枚举len的质因子,看能否消去这个因子,最后剩下的数就是答案。

      判断一个长度是否可以成立,可以用hash判断图中红色部分是否相等

      

      其中绿块长度为x。

      原理就是一开始解释过的KMP求最小循环节。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 501000
     5 #define p1 1000000007
     6 #define p2 998244353
     7 #define base 26
     8 #define LL long long
     9 
    10 int n, m, tot, top;
    11 int hash1[AC], hash2[AC], pw1[AC], pw2[AC];
    12 int pri[AC], last[AC], q[AC];
    13 char s[AC];
    14 bool z[AC];
    15 
    16 inline int read()
    17 {
    18     int x = 0;char c = getchar();
    19     while(c > '9' || c < '0') c = getchar();
    20     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    21     return x;
    22 }
    23 
    24 void get()//欧拉筛
    25 {
    26     for(R i = 2; i <= n; i ++)
    27     {
    28         if(!z[i]) pri[++ tot] = i, last[i] = i;
    29         for(R j = 1; j <= tot; j ++)
    30         {
    31             int now = pri[j];
    32             if(now * i > n) break;
    33             z[now * i] = true, last[now * i] = now;
    34             if(!(i % now)) break;
    35         }
    36     }
    37 }
    38 
    39 void pre()
    40 {
    41     n = read();
    42     scanf("%s", s + 1);
    43 }
    44 
    45 void build()//求前缀hash值
    46 {
    47     pw1[0] = pw2[0] = 1;
    48     for(R i = 1; i <= n; i ++) 
    49     {
    50         hash1[i] = (1ll * hash1[i - 1] * base + s[i] - 'a' + 1) % p1;
    51         hash2[i] = (1ll * hash2[i - 1] * base + s[i] - 'a' + 1) % p2;
    52         pw1[i] = 1ll * pw1[i - 1] * base % p1;//存下base的i次方
    53         pw2[i] = 1ll * pw2[i - 1] * base % p2;
    54     }
    55 }
    56 
    57 LL cal(int l, int r, bool w){
    58     if(!w) return ((1ll * hash1[r] - 1ll * hash1[l - 1] * pw1[r - l + 1] % p1) + p1) % p1;
    59     else return ((hash2[r] - 1ll * hash2[l - 1] * pw2[r - l + 1] % p2) + p2) % p2;
    60 }
    61 
    62 bool check(int l, int r, int x){//测试区间[l, r]的循环结是否可能为x
    63     return (cal(l + x, r, 0) == cal(l, r - x, 0)) && (cal(l + x, r, 1) == cal(l, r - x, 1));
    64 }
    65 
    66 void work()
    67 {
    68     m = read();
    69     for(R i = 1; i <= m; i ++)
    70     {
    71         int l = read(), r = read(), x = r - l + 1;
    72         top = 0;
    73         while(x != 1) q[++ top] = last[x], x /= last[x];
    74         x = r - l + 1;
    75         for(R i = 1; i <= top; i ++) 
    76             if(check(l, r, x / q[i])) x /= q[i];    
    77         printf("%d
    ", x);
    78     }
    79 }
    80 
    81 int main()
    82 {
    83 //    freopen("in.in", "r", stdin);
    84     pre();
    85     get();//处理last数组
    86     build();//构建hash数组
    87     work();
    88 //    fclose(stdin);
    89     return 0;
    90 }
    View Code

      

  • 相关阅读:
    mysql优化之索引优化
    mysqld --debug-sync
    mysql.cnf 配制文件详解
    my.cnf 中字符集设置
    tcp_tw_reuse 与 net.ipv4.tcp_tw_recycle
    mysql init_connect 参数的其他用处
    监控mysql索引使用效率的脚本
    mysql 源代码学习 博客 [lock..]
    mysqld with valgrind
    思维导图软件
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10066983.html
Copyright © 2011-2022 走看看