http://acm.hdu.edu.cn/showproblem.php?pid=4691
思路:其实关键就是求字符串任意两个子串的最长公共前缀,我们可以先求任意两个后缀的最长公共前缀,这可以用后缀自动机或者后缀数组解决,我这用的是后缀自动机,为了方便,我们可以将串反过来,然后求任意两前缀的最长公共后缀,我们建立完字符串的后缀自动机后,根据失败指针我们可以建立一棵树,和失败指针方向相反,那么我们知道任意一个前缀肯定由其中的一个节点来表示,求两个前缀的最长公共后缀就是求树中两个点的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; }