HDU 4691 Front compression (2013 多校联合9 1006)

来源:互联网 发布:江西网络干部学院app, 编辑:程序博客网 时间:2024/04/28 14:47

http://acm.hdu.edu.cn/showproblem.php?pid=4691


Front compression

Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)
Total Submission(s): 231    Accepted Submission(s): 88


Problem Description
Front compression is a type of delta encoding compression algorithm whereby common prefixes and their lengths are recorded so that they need not be duplicated. For example:

The size of the input is 43 bytes, while the size of the compressed output is 40. Here, every space and newline is also counted as 1 byte.
Given the input, each line of which is a substring of a long string, what are sizes of it and corresponding compressed output?
 

Input
There are multiple test cases. Process to the End of File.
The first line of each test case is a long string S made up of lowercase letters, whose length doesn't exceed 100,000. The second line contains a integer 1 ≤ N ≤ 100,000, which is the number of lines in the input. Each of the following N lines contains two integers 0 ≤ A < B ≤ length(S), indicating that that line of the input is substring [A, B) of S.
 

Output
For each test case, output the sizes of the input and corresponding compressed output.
 

思路:其实关键就是求字符串任意两个子串的最长公共前缀,我们可以先求任意两个后缀的最长公共前缀,这可以用后缀自动机或者后缀数组解决,我这用的是后缀自动机,为了方便,我们可以将串反过来,然后求任意两前缀的最长公共后缀,我们建立完字符串的后缀自动机后,根据失败指针我们可以建立一棵树,和失败指针方向相反,那么我们知道任意一个前缀肯定由其中的一个节点来表示,求两个前缀的最长公共后缀就是求树中两个点的LCA,LCA这里用树链剖分的思想来做,我们先要与处理处出每个节点所代表的串最长长度还有每个前缀在的树中节点的编号,然后求解更新答案即可。我们求完两个前缀的最长公共后缀之后,只需要和两个子串的长度取个小即可。具体实现可以参考代码。

#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <string.h>#include <stdio.h>#define ll long long#include <algorithm>#define maxn 200010using namespace std;struct node{    node *par,*go[26];    int val,num;}*root,*tail,que[maxn];int tot;char str[maxn>>1];void add(int c,int l){    node *p=tail,*np=&que[tot++];    np->val=l;    np->num=tot;    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;        else        {            node *nq=&que[tot++];            *nq=*q;            nq->num=tot;            nq->val=p->val+1;            np->par=q->par=nq;            while(p&&p->go[c]==q) p->go[c]=nq,p=p->par;        }    }    tail=np;}int len;struct edge{   int to,next;}e[maxn<<1];int box[maxn],cnt=0,po[maxn],pow[maxn];int siz[maxn],top[maxn],son[maxn],dep[maxn],fa[maxn];void init(int n){    int i;    for(i=0;i<=n;i++)    {        que[i].par=NULL;        que[i].val=0;        que[i].num=0;        memset(que[i].go,0,sizeof(que[i].go));    }    tot=0;    len=1;    root=tail=&que[tot++];    root->num=tot;    for(i=0;i<=n;i++)    box[i]=-1;    cnt=0;    son[0]=dep[0]=0;}void addv(int from,int to){    e[cnt].to=to;    e[cnt].next=box[from];    box[from]=cnt++;}void solve()//建图{    int i,tmp=0;    node *p=root;    //printf("tot=%d \n",tot);    for(;;p=p->go[str[p->val+1]-'a'])    {        po[tmp++]=p->num;        if(p->val==len-1)        break;    }    pow[1]=0;    for(i=1;i<tot;i++)    {        pow[que[i].num]=que[i].val;        int from=que[i].par->num,to=que[i].num;        addv(from,to);       // printf("%d %d\n",from,to);    }}void dfs(int now,int pre){    siz[now]=1;    fa[now]=pre;    son[now]=0;    dep[now]=dep[pre]+1;    int t,v,l;    for(t=box[now];t+1;t=e[t].next)    {        v=e[t].to;        if(v!=pre)        {            dfs(v,now);            siz[now]+=siz[v];            if(siz[son[now]]<siz[v])            {                son[now]=v;            }        }    }}void dfs2(int now,int tp){    top[now]=tp;    if(son[now])    dfs2(son[now],top[now]);    int t,v;    for(t=box[now];t+1;t=e[t].next)    {        v=e[t].to;        if(v!=fa[now]&&v!=son[now])        dfs2(v,v);    }}int LCA(int a, int b){    while (1)    {        if (top[a] == top[b])        return dep[a] <= dep[b] ? a : b;        else if (dep[top[a]] >= dep[top[b]])        a = fa[top[a]];        else b = fa[top[b]];    }}int getnum(ll x){    int sum=0;    if(x==0)    return 1;    while(x)    {        sum++;        x/=10;    }    return sum;}int main(){    freopen("dd.txt","r",stdin);    while(scanf("%s",str+1)!=EOF)    {        int n,i,l;        l=strlen(str+1);        init(l*2);        for(i=1;i<=(l/2);i++)        {            str[i]=str[i]^str[l-i+1];            str[l-i+1]=str[i]^str[l-i+1];            str[i]=str[i]^str[l-i+1];        }        for(i=1;i<=l;i++)        {            add(str[i]-'a',len++);        }        solve();        dfs(1,0);        dfs2(1,1);        scanf("%d",&n);        int pp=1,x,y,LL=0;        ll ansa=0,ansb=0;        while(n--)        {            scanf("%d%d",&x,&y);            ansa+=(y-x+1);            x++;            x=l-x+1;            y=l-y+1;            int now=po[x];            ll lca=(ll)LCA(now,pp);            lca=pow[lca];            lca=min(lca,min((ll)LL,(ll)x-y+1));            ansb+=x-y+1-lca+2+getnum(lca);            pp=now;            LL=x-y+1;        }        printf("%I64d %I64d\n",ansa,ansb);    }    return 0;}


原创粉丝点击