hdu 4821 String(hash)

来源:互联网 发布:揭阳网络广告公司 编辑:程序博客网 时间:2024/05/29 14:27

上来先枚举子串,hash了一发,超时,看了看数据,1e5的,不能这样搞了。。看到有博客说以l为一小段来枚举,想了想真是啊,这样时间复杂度就会降到很低。先枚举出一个长度为m*l的子串,然后去掉第一段l,后边加一段l,就是一个新的子串了,枚举到结束后,再从第二个字符开始这样枚举,一直枚举到以第l个字符开头就结束了。这样时间复杂度是O(n)

#include <bits/stdc++.h>using namespace std;typedef unsigned long long ull;const int MAXN = 1e5+10;char str[MAXN];ull h[MAXN];ull pp[MAXN];ull p = 31;map<ull,int> rec;int main(){    int m,l;    while(scanf("%d %d",&m,&l) != EOF)    {        scanf("%s",str);        int ll = m*l;        int len = strlen(str);        pp[0] = 1;        h[0] = 0;        for(int i = 1; i <= len; ++i)        {            h[i] = h[i-1]*p + str[i-1];            pp[i] = pp[i-1]*p;        }        int res = 0;        for(int i = 1; i <= l && i+ll-1 <= len; ++i)        {            rec.clear();            for(int j = i; j+l-1 <= i+ll-1; j += l)                rec[h[j+l-1]-h[j-1]*pp[l]]++;            if(rec.size() == m) ++res;            for(int j = ll+i; j+l-1 <= len; j += l)            {                rec[h[j-ll+l-1]-h[j-ll-1]*pp[l]]--;                if(rec[h[j-ll+l-1]-h[j-ll-1]*pp[l]] == 0)                    rec.erase(h[j-ll+l-1]-h[j-ll-1]*pp[l]);                rec[h[j+l-1]-h[j-1]*pp[l]]++;                if(rec.size() == m)++res;            }        }        printf("%d\n",res);    }    return 0;}
原创粉丝点击