zoukankan      html  css  js  c++  java
  • [十二省联考2019]字符串问题

    XIII.[十二省联考2019]字符串问题

    首先,我们可以把题目转变成这样:对于一些A类串,其有连向某些B类串的边;对于某些B类串,其又有连向某些A类串的边。要你找出一条权值最长的路径。(此时显然如果成环则答案一定是 \(-1\)

    A到B的串题目已经给出了,关键是B到A的串。

    我们发现,若某个 \(B\)\(A\) 的前缀,则 \(A\)\(B\) 在后面添加字符得到,需要在自动姬上搞,我们又不知道什么可以维护自动姬的结构;但是,如果我们把它转成后缀的话,就会发现这时我们变成了在parent tree上搞。处理一棵树可比处理DAG好多了,我们果断尝试这种思路。具体而言,我们翻转整个串,这样要求便变为了 \(B\)\(A\) 的后缀,即 \(B\) 所对应的节点在parent tree上是 \(A\) 的父亲。(当然,实际上我们会发现二者对应的节点可能相同,这时便要判断是否有 \(|A|\geq|B|\),若成立则 \(B\) 可以到 \(A\);为了统一两组情形,我们在相同节点处就把该节点按照长度不同拆开,这样就还是 \(A\) 节点的所有父亲上的 \(B\) 都连到 \(A\)

    这样处理完后,我们发现连到 \(A\) 的所有 \(B\) 在 parent tree 上成一条到根的路径。

    考虑将图中所有边反向,这时就变成了从最后一个 \(A\) 串到第一个 \(A\) 串的路径。然后,考虑将 parent tree 拷贝一份,一棵代表所有的 \(A\) 串,一棵代表所有的 \(B\) 串。现在,假设这两棵树上初始都没有边,考虑怎样连边让它符合我们的要求。

    首先,从最后一个 \(A\) 串出发,要能走到所有路径上的 \(B\) 串;因此,对于 \(A\) 树中每个节点,连到其在 \(B\) 树中对应的节点,并且在 \(B\) 树中让所有的儿子连到父亲,这样便实现了此过程。然后,\(B\) 还要能回到 \(A\),于是对于一组“支配关系”,直接让它从 \(B\) 上对应节点连到 \(A\) 上对应节点即可。这样搞完后,我们便得到了最终需要的图。

    52行极短代码,你值得拥有

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int T,n,m,A,B,cnt=1,id[200100],aa[200100],bb[200100],tot,val[1600100],in[1600100];
    ll f[1600100],res;
    char s[200100];
    struct Suffix_Automaton{int ch[26],len,fa;}t[400100];
    int Add(int x,int c){
    	int xx=++cnt;t[xx].len=t[x].len+1;
    	for(;x&&!t[x].ch[c];x=t[x].fa)t[x].ch[c]=xx;
    	if(!x){t[xx].fa=1;return xx;}
    	int y=t[x].ch[c];
    	if(t[y].len==t[x].len+1){t[xx].fa=y;return xx;}
    	int yy=++cnt;t[yy]=t[y],t[yy].len=t[x].len+1;
    	t[xx].fa=t[y].fa=yy;
    	for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
    	return xx;
    }
    int anc[400100][20];
    map<int,int>mp[400100];
    int substring(int l,int r){//give the substring (l,r) of the original string an identifier
    	l=n-l,r=n-r,swap(l,r);
    	int x=id[r];
    	for(int j=19;j>=0;j--)if(anc[x][j]&&t[anc[x][j]].len>=r-l+1)x=anc[x][j];
    	if(!mp[x][r-l+1])mp[x][r-l+1]=++tot;
    	return mp[x][r-l+1];
    }
    vector<int>v[1600100];
    void ae(int x,int y){v[x].push_back(y),in[y]++;}
    queue<int>q;
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		scanf("%s",s),n=strlen(s),reverse(s,s+n);//reverse the string, making prefix into suffix.
    		for(int i=0,las=1;i<n;i++)id[i]=las=Add(las,s[i]-'a');
    		for(int i=1;i<=cnt;i++)mp[i][t[i].len]=++tot,anc[i][0]=t[i].fa;
    		for(int j=1;j<=19;j++)for(int i=1;i<=cnt;i++)anc[i][j]=anc[anc[i][j-1]][j-1];
    		scanf("%d",&A);for(int i=1,l,r;i<=A;i++)scanf("%d%d",&l,&r),val[aa[i]=substring(l,r)]=r-l+1;
    		scanf("%d",&B);for(int i=1,l,r;i<=B;i++)scanf("%d%d",&l,&r),bb[i]=substring(l,r);
    		for(int i=2;i<=cnt;i++)for(auto it=mp[i].rbegin();it!=mp[i].rend();){
    			auto ti=it++;
    			ae(tot+ti->second,tot+(it==mp[i].rend()?mp[t[i].fa].rbegin():it)->second);
    		}
    		scanf("%d",&m);for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),ae(bb[y]+tot,aa[x]);
    		for(int i=1;i<=tot;i++)ae(i,tot+i);for(int i=1;i<=2*tot;i++)if(!in[i])q.push(i);
    		while(!q.empty()){int x=q.front();q.pop(),f[x]+=val[x];for(auto y:v[x]){f[y]=max(f[y],f[x]);if(!--in[y])q.push(y);}}
    		for(int i=1;i<=2*tot;i++)if(in[i]){res=-1;break;}else res=max(res,f[i]);printf("%lld\n",res),res=0;
    		for(int i=1;i<=cnt;i++)memset(t[i].ch,0,sizeof(t[i].ch)),t[i].len=t[i].fa=0,mp[i].clear();cnt=1;
    		for(int i=1;i<=2*tot;i++)v[i].clear(),val[i]=in[i]=f[i]=0;tot=0;
    	}
    	return 0;
    }
    

  • 相关阅读:
    设计模式开始--工厂模式
    设计模式开始--UML类之间关系表示
    设计模式开始1--不明觉厉
    Gas Station
    Validate Binary Search Tree
    Word Ladder
    (转)基于快速排序的TOPK算法
    Number of 1 Bits
    Word Search
    Rotate Array
  • 原文地址:https://www.cnblogs.com/Troverld/p/14605724.html
Copyright © 2011-2022 走看看