日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【十二省联考2019】字符串问题【后缀自动机】【拓扑排序】

發(fā)布時(shí)間:2023/12/4 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【十二省联考2019】字符串问题【后缀自动机】【拓扑排序】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題意:給一個(gè)字符串 SSS,以子串的形式給出一些 A 類串和 B 類串以及 mmm 對(duì) A 類串支配 B 類串的關(guān)系。求一個(gè)總長(zhǎng)度最長(zhǎng)的 A 類串序列,使得每個(gè)串都存在一個(gè) B 類串前綴被后一個(gè)串支配。無(wú)窮輸出 ?1-1?1

∣S∣,m≤2×105|S|,m\leq 2\times 10^5S,m2×105

顯然需要先把反串 SAM 建出來(lái),然后樹(shù)上倍增定位每個(gè)子串。

對(duì)于每一步,相當(dāng)于是可以不斷丟掉最后一個(gè)字符變成前綴,如果是個(gè) B 類串,可以走到一個(gè)被支配的 A 類串。

所以 SAM 上每個(gè)點(diǎn)向 fail 樹(shù)上的父親連一條 000 的邊, uuu 支配 vvv 就從 vvvuuu∣u∣|u|u 的邊。然后拓?fù)渑判蚝笞鲎铋L(zhǎng)路即可。因?yàn)闆](méi)有 000 環(huán),也沒(méi)有不聯(lián)通等奇奇怪怪的東西,所以有環(huán)就是 ?1-1?1

然后這道題就做完了……

才怪。你的 A,B 類串定位的是一類子串,而限制是死的。具體來(lái)說(shuō),一個(gè) B 類串定位到了某個(gè)結(jié)點(diǎn)的一坨子串上,然后一個(gè) A 類串定位也定位到了這個(gè)結(jié)點(diǎn),而且還比 B 類串短,那么它是不能走到這個(gè) B 的。但是 SAM 上它們是同一個(gè)結(jié)點(diǎn),所以上面的算法就會(huì)出錯(cuò)。

怎么辦?拆了唄

當(dāng)然不用真的拆了,把這些定位的點(diǎn)放結(jié)點(diǎn)的 vector 里,然后在內(nèi)部排序建一下就可以了。

不算難寫,單純的碼量大。

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <vector> #include <utility> #include <queue> #include <algorithm> #define MAXN 800005 #define MAXM 1200005 using namespace std; typedef long long ll; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } char s[MAXN]; int ch[MAXN][26],len[MAXN],fa[MAXN],las=1,tot=1; void insert(int c) {int cur=++tot;len[cur]=len[las]+1;int p=las;for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;if (!p) fa[cur]=1;else{int q=ch[p][c];if (len[q]==len[p]+1) fa[cur]=q;else{int _q=++tot;len[_q]=len[p]+1;fa[_q]=fa[q],fa[cur]=fa[q]=_q;memcpy(ch[_q],ch[q],sizeof(ch[_q]));for (;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=_q;}}las=cur; } int up[MAXN][20]; inline void build() {for (int i=1;i<=tot;i++) up[i][0]=fa[i];for (int j=1;j<20;j++)for (int i=1;i<=tot;i++)up[i][j]=up[up[i][j-1]][j-1]; } inline int find(int x,int l) {for (int i=19;i>=0;i--)if (len[up[x][i]]>=l)x=up[x][i];return x; } int na,nb,la[MAXN],lb[MAXN],ra[MAXN],rb[MAXN]; struct node { int idx,type;inline int len()const{return type? ra[idx]-la[idx]+1:rb[idx]-lb[idx]+1;}inline int pos()const{if (type==1) return tot+idx;if (type==0) return tot+na+idx;return idx;} }; inline bool operator <(const node& a,const node& b){return a.len()<b.len()||(a.len()==b.len()&&a.type<b.type);} vector<node> lis[MAXN]; struct edge{int u,v,w;}e[MAXM]; int head[MAXN],nxt[MAXM],deg[MAXN],cnt; inline void addnode(int u,int v,int w) {e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt;++deg[v]; } int pos[MAXN],dfn[MAXN],tim; ll dp[MAXN]; int q[MAXN],qs,qt; void clear() {for (int i=1;i<=tot;i++) {memset(ch[i],0,sizeof(ch[i])),fa[i]=len[i]=0;memset(up[i],0,sizeof(up[i]));vector<node>().swap(lis[i]);}for (int i=1;i<=tot+na+nb+1;i++) head[i]=deg[i]=dp[i]=0;for (int i=1;i<=cnt;i++) nxt[i]=0;tim=cnt=0,las=tot=1; } int main() {for (int T=read();T;T--){scanf("%s",s+1);int n=strlen(s+1);for (int i=n;i>=1;i--) insert(s[i]-'a'),pos[i]=las;build(); na=read();for (int i=1;i<=na;i++){la[i]=read(),ra[i]=read();lis[find(pos[la[i]],ra[i]-la[i]+1)].push_back((node){i,1});}nb=read();for (int i=1;i<=nb;i++){lb[i]=read(),rb[i]=read();lis[find(pos[lb[i]],rb[i]-lb[i]+1)].push_back((node){i,0});}for (int i=1;i<=tot;i++) {sort(lis[i].begin(),lis[i].end());lis[i].push_back((node){i,-1});if (fa[i]) addnode(lis[i].front().pos(),fa[i],0);for (int j=0;j<(int)lis[i].size()-1;j++) addnode(lis[i][j+1].pos(),lis[i][j].pos(),0);}for (int m=read();m;m--){int u,v;u=read(),v=read();addnode(tot+na+v,tot+u,ra[u]-la[u]+1);}int S=tot+na+nb+1;for (int i=1;i<=na;i++) addnode(S,tot+i,ra[i]-la[i]+1);qs=1,qt=0;for (int i=1;i<=S;i++) if (!deg[i]) q[++qt]=i;while (qs<=qt){int u=dfn[++tim]=q[qs++];for (int i=head[u];i;i=nxt[i])if (!(--deg[e[i].v]))q[++qt]=e[i].v;}if (tim<S) puts("-1");else{for (int k=S;k>=1;k--){int u=dfn[k];for (int i=head[u];i;i=nxt[i])dp[u]=max(dp[u],dp[e[i].v]+e[i].w);}printf("%lld\n",dp[S]);}clear();}return 0; }

總結(jié)

以上是生活随笔為你收集整理的【十二省联考2019】字符串问题【后缀自动机】【拓扑排序】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。