zoukankan      html  css  js  c++  java
  • BZOJ 2795: [Poi2012]A Horrible Poem (Hash+思维)

    给定字符串,求给定l,r区间的最短循环节长度.

    显然区间长度循环节长度是区间长度m的因数,但是这样直接写个q根号m的暴力就肯定T掉啦。

    想了挺久发现了一个喵喵的做法,不难发现,每个区间的某个字母必须在一个循环节里都出现,若这个字母出现k次,那么循环节的个数必须是k的因数,那么循环节个数就在这个区间gcd(k)范围内.

    我们可以先预处理出前缀和数组保存每个区间每个字母出现次数,预处理除字符串hash值,然后枚举到根号gcd就够了.

    这样复杂度是q根号gcd(k),十分玄学的复杂度,于是我在洛谷和loj就T成了90分,可能代码写丑了吧,不过在bzoj上AC了。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 #include <queue>
     7 #include <map>
     8 #define ll long long
     9 #define out(a) printf("%d",a)
    10 #define writeln printf("
    ")
    11 const int N=5e5+50;
    12 const int MOD=1e9+7;
    13 const int base=233;
    14 using namespace std;
    15 int n,q,l,r,ln;
    16 int num,numn,numns,len,ans=0;
    17 ll Hash[N],Pow[N];
    18 int cnt[27][N];
    19 char s[N];
    20 int read()
    21 {
    22     int s=0,t=1; char c;
    23     while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();}
    24     while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();}
    25     return s*t;
    26 }
    27 ll readl()
    28 {
    29     ll s=0,t=1; char c;
    30     while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();}
    31     while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();}
    32     return s*t;
    33 }
    34 ll get(int l,int r)
    35 {
    36     if (l<=r) return (Hash[r]-(ll)Hash[l-1]*Pow[r-l+1]%MOD+MOD)%MOD;
    37     return 0;
    38 }
    39 void hashs(char s[])
    40 {
    41     for (int i=0;i<n;i++)
    42       Hash[i]=(Hash[i-1]*base+s[i])%MOD;
    43 }
    44 int gcd(int a,int b)
    45 {
    46     return a==0?b:gcd(b%a,a);
    47 }
    48 int main()
    49 {
    50     n=read(); Pow[0]=1;
    51     for (int i=1;i<=n;i++)
    52       Pow[i]=Pow[i-1]*base%MOD;
    53     scanf("%s",s); ln=strlen(s);
    54     for (int i=1;i<=26;i++)
    55       for (int j=0;j<ln;j++){
    56         cnt[i][j]=cnt[i][j-1];
    57         if (s[j]-'a'+1==i) cnt[i][j]++;
    58     }
    59     hashs(s);
    60     q=read();
    61     for (int i=1;i<=q;i++){
    62       l=read(),r=read(); len=r-l+1; ans=num=len; l--; r--; 
    63       for (int i=1;i<=26;i++)
    64         num=gcd(num,cnt[i][r]-cnt[i][l-1]);
    65       for (int i=1;i*i<=num;i++){
    66         if (num%i==0){
    67             numns=len/(num/i); 
    68           if (get(l+numns,r)==get(l,r-numns)) {
    69             ans=numns; break;
    70           }
    71           numn=len/i; 
    72           if (get(l+numn,r)==get(l,r-numn)){
    73               ans=numn; 
    74           }
    75         }
    76       }
    77       out(ans); 
    78       writeln;
    79     }
    80     return 0;
    81 }
    View Code
  • 相关阅读:
    Sql 字符串按指定字符转多行(表值函数)
    C# 默认打印机设置
    Sql server 触发器状态查询
    指定周转对应日期
    Java发送HttpRequest
    Java实现手机号码归属地判别
    MySQL导入.sql文件及常用命令
    解释和编译的区别
    Java中的static关键字解析
    内存堆和栈的区别
  • 原文地址:https://www.cnblogs.com/Kaleidoscope233/p/9563058.html
Copyright © 2011-2022 走看看