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
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?
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.
思路:其實關鍵就是求字符串任意兩個子串的最長公共前綴,我們可以先求任意兩個後綴的最長公共前綴,這可以用後綴自動機或者後綴數組解決,我這用的是後綴自動機,爲了方便,我們可以將串反過來,然後求任意兩前綴的最長公共後綴,我們建立完字符串的後綴自動機後,根據失敗指針我們可以建立一棵樹,和失敗指針方向相反,那麼我們知道任意一個前綴肯定由其中的一個節點來表示,求兩個前綴的最長公共後綴就是求樹中兩個點的LCA,LCA這裏用樹鏈剖分的思想來做,我們先要與處理處出每個節點所代表的串最長長度還有每個前綴在的樹中節點的編號,然後求解更新答案即可。我們求完兩個前綴的最長公共後綴之後,只需要和兩個子串的長度取個小即可。具體實現可以參考代碼。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#define ll long long
#include <algorithm>
#define maxn 200010
using 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;
}