您的位置:首页 > 其它

2013多校联合4 1010 K-string (hdu 4641)

2013-08-01 20:04 387 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4641


K-string

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 102400/131072 K (Java/Others)

Total Submission(s): 24    Accepted Submission(s): 11


Problem Description

Given a string S. K-string is the sub-string of S and it appear in the S at least K times.It means there are at least K different pairs (i,j) so that Si,Si+1... Sj equal to this K-string. Given m operator or query:1.add a letter
to the end of S; 2.query how many different K-string currently.For each query ,count the number of different K-string currently.

 

Input

The input consists of multiple test cases. 

Each test case begins with a line containing three integers n, m and K(1<=n,K<=50000,1<=m<=200000), denoting the length of string S, the number of operator or question and the least number of occurrences of K-string in the S.

The second line consists string S,which only contains lowercase letters. 

The next m lines describe the operator or query.The description of the operator looks as two space-separated integers t c (t = 1; c is lowercase letter).The description of the query looks as one integer t (t = 2).

 

Output

For each query print an integer — the number of different K-string currently.

思路:赛后才发现,其实过这道题完全是因为运气好,题目数据不强,赛后被光林大神的一个极限数据卡了几十秒都没跑出来。。。不过还是说说我的思路吧,我使用后缀自动机写的,首先在后缀自动机的每个节点中除了常规的val外,再设置两个变量,num表示这个节点所表示的子串在当前字符串中所出现的次数,flag表示该节点所表示的子串是否已经超过K,那么我们在将一个字符加入后缀自动机时,更新ans,因为一个子串的出现次数只和它的right集合有关,而只有当一个节点,有新的节点的par指针指向它时,它的right集合才会改变,多以我们只要将一个新节点加入原SAM后,从它开始沿着par指针一直向上更新,因为一个节点的父节点的出现次数一定比该节点大,所以一个显然易见的优化就是当走到一个节点,它的num已经不小于K时就停止(即flag为1)。虽然这样的程序已经可以过这道题的所有数据,但是事实上还是有数据惠超时,比如对于k很大时,且加入的字符全是一样的,这样的话,构造的后缀自动机就会是一条链,那么我们更新节点时,会一直遍历很多次才能结束,所以必定超时,对于这样的数据,我的一个想法是用一个数据结构(平衡树,树状数组,线段树什么的)将SAM存起来,然后利用该数据结构更新节点即可,但是还没有实践,这里先贴一个最原始的代码,仅供参考。

#include <iostream>
#include <string.h>
#include <stdio.h>
#define maxn 500010
#define ll long long
#define Smaxn 26
using namespace std;
struct node
{
node *par,*go[Smaxn];
int num,flag;
int val;
}*root,*tail,que[maxn];
int tot;
ll ans=0;
int n,m,k;
void add(int c,int l)
{
node *p=tail,*np=&que[tot++];
np->val=l;
np->num=1;
if(k==1)
{
np->flag=1;
ans++;
}
while(p&&p->go[c]==NULL)
p->go[c]=np,p=p->par;
if(p==NULL) np->par=root;
else
{
node *q=p->go[c];
if(p->val+1==q->val)
{
np->par=q;
node *tmp=q;
while(tmp!=root)
{
if(tmp->flag==1)
break;
tmp->num++;
if(tmp->num>=k&&tmp->flag==0)
{
ans+=tmp->val-tmp->par->val;
tmp->flag=1;
}
tmp=tmp->par;
}
}
else
{
node *nq=&que[tot++];
*nq=*q;
nq->val=p->val+1;
np->par=q->par=nq;
while(p&&p->go[c]==q) p->go[c]=nq,p=p->par;
node *tmp=nq;
while(tmp!=root)
{
if(tmp->flag==1)
break;
tmp->num++;
if(tmp->num>=k&&tmp->flag==0)
{
ans+=tmp->val-tmp->par->val;
tmp->flag=1;
}
tmp=tmp->par;
}

}
}
tail=np;
}
char str[maxn>>1];
int len;
void init(int n)
{
int i;
for(i=0;i<=n;i++)
{
que[i].num=que[i].val=que[i].flag=0;
que[i].par=NULL;
memset(que[i].go,0,sizeof(que[i].go));
}
ans=0;
tot=0;
len=1;
root=tail=&que[tot++];
}
int main()
{
// freopen("dd.txt","r",stdin);
// freopen("output.txt","w",stdout);
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
scanf("%s",str);
int i,l=strlen(str);
init(2*(l+m));
for(i=0;i<l;i++)
{
add(str[i]-'a',len++);
}
int q;
char tmp[2];
while(m--)
{
scanf("%d",&q);
if(q==1)
{
scanf("%s",tmp);
add(tmp[0]-'a',len++);
}
else
printf("%I64d\n",ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: