您的位置:首页 > 其它

HDU4821(2013 Asia Regional Changchun - I)

2016-09-08 12:07 176 查看
Problem : String

Description :

给你一个字符串S,让你求出符合条件的子串的数量: 子串的长度是M∗L,同时这个子串分成M个长度为L的小子串后两两不相同。

Solution :

字符串hash算法(BKDRHash)+暴力美学。字符串的这个hash算法我是看别人的,我是真的不知道还有这么个东西,我自己想的hash与之类似,不过我的权数是26,而它的权数是31。暴力部分就是我的作品了,暴力美学。对于每个子串的hash值只能用用公式计算,而不能模拟!而子串又是一个区间问题,那么就可以先预处理出1→i的哈希值,然后用公式hashvalue[e]−hashvalue[s]∗POWER[e−s]计算出来就好了。之后就是对M个小子串进行比较了,这里我们用map来比较,如果把M个小子串的哈希值放进去后发现map的容量为M,那么就满足条件了。对于后续的小子串处理,我们把之前的M个子串中的第一个位置除去,再加上接下来的一个子串。这样就构成了一个新的子串,我们判断这个新的map容量是不是符合条件就可以了,如何做到这个呢,我用了一个队列来动态保存这M个子串。最后一点,我们为了避免重复,可以利用希尔排序的分组的思想,把S分成L个组,这样分出来判断就绝对不会重复了。

Code(C++) :

#include <stdio.h>
#include <string.h>

#include <map>
#include <queue>

using namespace std;

typedef unsigned long long ULL;

const int MAXN=100000+5;
const int base=31;

char str[MAXN];
int M,L;
int len;

ULL hash_value[MAXN];
ULL POWER[MAXN];

void init()
{
POWER[0]=1;
for(int i=1;i<MAXN;i++)
POWER[i]=POWER[i-1]*base;
}

ULL get_hash(int s,int e)
{
if(s<0)
return hash_value[e];
return hash_value[e]-hash_value[s]*POWER[e-s];
}

int main()
{
//freopen("in","r",stdin);
init();
while(~scanf("%d%d",&M,&L)){
scanf("%s",str);
len=strlen(str);
for(int i=0;i<MAXN;i++)
hash_value[i]=0;
hash_value[0]=str[0]-'a'+1;
for(int i=1;i<len;i++)
hash_value[i]=(hash_value[i-1]*base+str[i]-'a'+1);
map<ULL,int> m;
queue<ULL> que;
int ans=0;
for(int i=0;i<L&&i+M*L<=len;i++){
m.clear();
while(!que.empty())
que.pop();
for(int j=i;j+L<=i+M*L;j+=L){
ULL tmp=get_hash(j-1,j+L-1);
++m[tmp];
que.push(tmp);
}
if(m.size()==M)
++ans;
for(int j=i+M*L;j+L<=len;j+=L){
ULL head=que.front();
que.pop();
--m[head];
if(m[head]==0)
m.erase(head);
ULL tail=get_hash(j-1,j+L-1);
++m[tail];
que.push(tail);
if(m.size()==M)
++ans;
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: