hdu 4821 String

来源:互联网 发布:js对象转json字符串 编辑:程序博客网 时间:2024/05/29 15:12

这两天做了几道题,跑来总结总结。

这道题到手先是读傻了。思来想去不得正解。百度了一下看到字符串Hash,立马关掉。又是一个陌生的术语。

找了些资料后先是做了poj1200,上手了字符串Hash。换句话说是BKDRHash。

简单的介绍一下。

unsigned int BKDRHash(char * str){unsigned int base = 31; //131 1331 13331 ...unsigned int hash = 0;while (*str){hash = hash*base + (*str++);}return hash;}
这个函数可以把一个字符串转化成一个数字。
先去感受一下吧。

当你对BKDRHash有了一定概念以后。进入正文。

----------------------------------------------------------------------------------------------------------------------

遍历开头,也就是前L个字符。

然后把每L个字符转换成一个数字保存在数组中。

问题就转化成为求一个数组中连续的不相同的长度为m的子串。

用一个小技巧预处理一下可以让字符转化的复杂度降为O(n)。

求字符串前i个字符的Hash值。得到num[i]。

那么 i- j 对应的字符串所代表的数字为 num[j]-num[i]*p[j-i+1];

p为base对自己的累乘。不明白就看代码,一目了然。

问题传化后见变成了一个简单计数问题了。

#include<iostream>#include<cstdio>#include<cstring>#include<map>using namespace std;typedef unsigned __int64 ULL;const int N = 1e5 + 10;char s[N];ULL num[N];ULL p[N];int m, l;map<ULL, int> mp;ULL base = 31;ULL t[N];int cnt;int main(){p[0] = 1;for (int i = 1; i < N; i++)p[i] = p[i - 1] * base;while (~scanf("%d%d%s", &m, &l, s)){int len = strlen(s);int i, j;ULL Hash = 0;//mp.clear();memset(num,0,sizeof(num));for (i = 1; i <= len ; ++i){num[i] = num[i - 1] * base + s[i-1] - 'a';}int ml = m*l;int ans = 0;for (i = 0; i < l; ++i){int tmp = 0;cnt = 0;for (j = i + 1; j + l - 1 <= len; j += l){ULL Hash = num[j + l - 1] - num[j - 1] * p[l];t[cnt++] = Hash;/*//cout << Hash << endl;if (mp[Hash] == false)tmp++;else{mp.clear();if (tmp >= m){ans += tmp - m + 1;tmp = tmp%m;j -= tmp*l;tmp = 0;}else tmp = 1;}mp[Hash] = true;}if (tmp >= m)ans += tmp - m + 1;//cout << endl;*/}mp.clear();for (j = 0; j < cnt; j++){if (mp.find(t[j]) == mp.end()){mp[t[j]] = j;tmp++;}else if (j - mp[t[j]] + 1 > m){mp[t[j]] = j;tmp++;}else if(tmp>=m){ans += tmp - m + 1;j = mp[t[j]];tmp = 0;mp.clear();}else{j = mp[t[j]];tmp = 0;mp.clear();}}if (tmp >= m){ans += tmp - m + 1;}}printf("%d\n" , ans );}return 0;}/*3 3qwertyuiopasqwefghjkl*/


0 0
原创粉丝点击