您的位置:首页 > 其它

HDU 4622 Reincarnation

2015-06-24 02:55 363 查看
题目大意:

给定一个基础字符串,再给多个字符串,求出基础字符串中能得到的不一样的子串的个数未出现在后面多个字符串当中

这里以基础子串构建后缀自动机是没问题的

后面的多个子串不断在后缀自动机上进行匹配,每次到达一个状态点,就要更新当前点所能达到的其他字符串抵达最大长度 mx,那么未能匹配的长度就是cur->l-mx

因为父节点受子节点影响,所以要拓扑排序,不断更新父节点所能达到的最大长度,最后统计所有数量之和即可

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

#define N 100010
#define ll long long
struct SamNode{
SamNode *son[26] , *f;
int l , mx;
void init(){
for(int i=0 ; i<26 ; i++) son[i] = NULL;
f=NULL;
l = mx = 0;
}
}sam[N<<1] , *root , *last , *b[N<<1];

int cnt , num
;
ll ret;
char s
;

void add(int x)
{
SamNode *p = &sam[++cnt] , *jp = last;
p->init();
p->l = jp->l+1 ;
last = p;
for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
if(!jp) p->f = root;
else{
if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
else{
SamNode *r = &sam[++cnt] , *q = jp->son[x];
r->init();
*r = *q;
r->l = jp->l+1;
p->f = q->f = r;
for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
}
}
}

void solve(int n , int &cas)
{
int l , len=strlen(s);
memset(num , 0 , sizeof(num));
for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++;
for(int i=1 ; i<=len ; i++) num[i]+=num[i-1];
for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]]=&sam[i];
for(int i=0 ; i<n ; i++){
scanf("%s" , s);
l=strlen(s) , len=0; //len表示当前所能达到的最大长度
SamNode *cur = root;
for(int j=0 ; j<l ; j++){
int x = s[j]-'a';
if(cur->son[x]){
len++;
cur = cur->son[x];
cur->mx = max(cur->mx , len);
}else{
while(cur&&!cur->son[x]) cur=cur->f;
if(!cur)
cur = root , len=0;
else{
len = cur->l+1;
cur = cur->son[x];
cur->mx = max(cur->mx , len);
}
}
}
}
ll ret = 0;
for(int i=cnt ; i>=1 ; i--){
// cout<<i<<" "<<b[i]->l<<" "<<b[i]->mx<<endl;
if(b[i]->mx) ret = ret + (b[i]->l-b[i]->mx>=0?b[i]->l-b[i]->mx:0);
else ret = ret + b[i]->l-b[i]->f->l;
b[i]->f->mx = max(b[i]->f->mx , b[i]->mx);
}
printf("Case %d: %I64d\n" , ++cas , ret);
}

int main()
{
// freopen("a.in" , "r", stdin);
int T , n , cas=0;
scanf("%d" , &T);
while(T--)
{
scanf("%d%s" , &n , s);
int l = strlen(s);
sam[0].init();
root = last = &sam[cnt=0] , ret = 0;
for(int i=0 ; i<l ; i++)
add(s[i]-'a');
solve(n , cas);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: