BZOJ 1355 [Baltic2009]Radio Transmission Hash/KMP

来源:互联网 发布:linux创建目录命令 编辑:程序博客网 时间:2024/05/18 01:14

题意:
给定一个字符串求最小循环节。
解析:
显然我们可以hash然后枚举长度判断。
复杂度O(n/1+n/2+n/3+….+n/n)=O(nlogn)
然而KMP中next数组有一个性质。
n-next[n]恰好是最小循环节长度。
所以O(n)即可解决。
代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 1000100#define base 1313131using namespace std;typedef unsigned long long ull;int n;ull hash[N],pow[N];char s[N];ull get_hash(int l,int r){    return hash[r]-hash[l-1]*pow[r-l+1];}bool check(int len){    if(len==n)return 1;    ull tmphash=0;    int i;    for(i=1;i+len-1<=n;i+=len)    {        if(!tmphash){tmphash=get_hash(i,i+len-1);continue;}        if(get_hash(i,i+len-1)==tmphash)continue;        else return 0;    }    if(i<=n)    {        int tmplen=n-i+1;        if(get_hash(1,tmplen)==get_hash(n-tmplen+1,n))return 1;        else return 0;    }    return 1;}int main(){    scanf("%d",&n);    scanf("%s",s+1);pow[0]=1;    for(int i=1;i<=n;i++)        pow[i]=pow[i-1]*base,hash[i]=hash[i-1]*base+s[i];    int l=1,r=n,ans;    for(int i=1;i<=n;i++)    {        if(check(i)){ans=i;break;}    }    printf("%d\n",ans);}
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 1000100using namespace std;int n;char s[N];int ne[N];void getnext(){    ne[0]=-1;    int i=0,j=-1;    while(i<n)    {        if(j==-1||s[i]==s[j])        {            i++,j++;            ne[i]=j;        }else j=ne[j];    }}int main(){    scanf("%d",&n);    scanf("%s",s);    getnext();    printf("%d\n",n-ne[n]);}
0 0
原创粉丝点击