HDU - 4821 (暴力的复杂度计算)

来源:互联网 发布:广州周立功单片机公司 编辑:程序博客网 时间:2024/05/15 14:21

本题目意思:

给定一个长度为1E5的串,给定N,M,让统计所有的连续子串,满足串长为N*M,而且这N个长为M的串两两不相同,输出个数。

分析:

本题目明显使用哈希来做的,因为在LONG LONG 内散列不超过 1E5个子串,出现冲突的概率极低。

然后不能从头暴力算出第一个长为N*M的串每个长M的哈希值,然后递推计算后面的每个长为N*M串的hash值,这样复杂度为(len - N*M)*(N*log(M))很容易被卡掉的,算一下就清楚。

那么,暴力的方法是:

记hash(1->m),为远串位置从1->m的子串的hash值,先计算出所有的 hash( k*m+1 , (k+1)*m),

那么第一个长为N*M的串的hash集合为上面的K 取 0 - > n-1; 那么  位置在 m+1 - > (n+1)*m的子串的哈希集合就是在前面的基础上在前面去掉一个,在后面加上一个,

那么用map维护hash集合的变动,每个这样的串的复杂度为o(log(m))

所以加上递推初始所有hash值,总复杂度 m*(len / m) + (len - n*m)*log(m),这样的复杂度组大不超过 len*log(M),所以可以ac;

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <map>#include <cmath>#include <cctype>#define rep1(i,x,y) for(int i=x;i<=y;i++)using namespace std;typedef long long LL;const int base = 131;const int N = 101010;const LL mod = 1e16;char str[N];int n,m;LL ha[N];map<LL,int> M;int main(){    memset(str,0,sizeof(str));    while(scanf("%d %d",&n,&m)==2){       scanf("%s",str+1);       int len = strlen(str+1), all = len/m; LL tem = 0;       rep1(i,1,len){            tem=(tem*base+str[i])%mod; if(i%m == 0) {ha[i/m]=tem; tem=0;}       }       LL ba = 1; rep1(i,1,m-1) ba=ba*base%mod;       int res = 0;       rep1(i,1,m){            if(i + n*m -1 > len) break;            M.clear();            if(i > 1){               rep1(j,1,all){                   ha[j]=(ha[j]-ba*str[(j-1)*m+i-1]+mod)%mod;                   ha[j]=(ha[j]*base+str[j*m+i-1])%mod;                   if(j<=n) M[ha[j]]++;               }            }            else rep1(j,1,n) M[ha[j]]++;            if(M.size() == n) res++;            for(int st = i+n*m-1+m,j=1; st<=len;st+=m,j++){                 M[ha[j]]--; M[ha[j+n]]++;                 if(M[ha[j]] == 0) M.erase(ha[j]);                 if(M.size() == n) res++;            }       }       printf("%d\n",res);    }    return 0;}




0 0
原创粉丝点击