#zrO xtx Orz 感受就是抄了一遍https://zybuluo.com/AntiLeaf/note/804022 不得不說,這個作法很是強。 因爲博主水平有限,有可能有一些純感性理解的東西.c++
首先,最長反鏈這個說法彷佛有一些問題,這裏的反鏈是指互不包含的點集。 最小可重路徑覆蓋指邊和點均可以重複. 最小不可重路徑覆蓋指點不重複.閉包
這樣根據dilworth定理,這個東西對應最小鏈剖分,也就是求出傳遞閉包並連邊後的DAG的最小不可重路徑覆蓋。優化
最小不可重路徑覆蓋仍是比較簡單的. 他有一個經典作法,拆點建二分圖,原點向左邊的點連邊,容量爲1,左邊的點向右邊的點連原圖的邊,容量爲1,右邊的點向匯點連邊,容量爲1. 考慮一個匹配的含義就是原來的$n$個路徑中的兩個結合了. 那麼答案就是點數減最大匹配數.ui
最小可重路徑覆蓋,第一種作法是求出傳遞閉包,而後轉化爲不可重,可是點數較多時並不能求出傳遞閉包. 另外一種作法考慮優化建圖,原來的邊的含義是直接或間接到達,如今的邊只有直接到達的含義,那麼爲了可讓間接到達存在,每一個點的入點向出點連Inf邊,而且原圖的邊連Inf.url
若是這個問題的最長反鏈是一個點集的呢? 只須要源點只向該點集連邊,只有該點集向匯點連邊便可,由於考慮其餘的邊和點都是維護是否可達關係的輔助邊和點.spa
一個用到這個的題的代碼.net
#include <bits/stdc++.h> using namespace std; const int N=100005; char ss[N]; int fa[N]; int len[N]; int trans[N][26],la,tot=1; int s,t; int aa[N]; int val[N]; int getfail(char *s,int x,int r){ while (s[r]!=s[r-len[x]-1]){ x=fa[x]; //cerr<<x<<" "<<len[x]<<endl; } return x; } void init(){ len[0]=0; len[1]=-1; fa[0]=1; } void build(char *s,int l,int r){ //cerr<<"BBBB"<<" "<<la<<endl; char c=s[r]-'a'; int cur=getfail(s,la,r); //cerr<<"cur"<<cur<<endl; if (!trans[cur][c]){ ++tot; len[tot]=len[cur]+2; fa[tot]=trans[getfail(s,fa[cur],r)][c]; //cerr<<"tot"<<tot<<" "<<fa[tot]<<" "<<cur<<endl; trans[cur][c]=tot; } la=trans[cur][c]; val[la]=max(val[la],aa[r]); //cerr<<"build"<<l<<" "<<r<<endl; } struct edge{ int y,cap,op; }; int pp=0; vector<edge> g[N+N]; void add(int x,int y,int z){ //cerr<<"add"<<x<<" "<<y<<" "<<z<<" "<<++pp<<endl; g[x].push_back({y,z,g[y].size()}); g[y].push_back({x,0,g[x].size()-1}); } int cur[N+N],d[N+N]; bool bfs(){ queue<int> q; q.push(s); for (int i=s; i<=t; ++i) cur[i]=d[i]=0; d[s]=233; while (!q.empty()){ int x=q.front(); q.pop(); //cerr<<"XXXXXXXXXXXX"<<x<<" "<<g[x].size()<<endl; for (auto j:g[x]){ //cerr<<"cap"<<j.cap<<endl; if (j.cap&&!d[j.y]){ //cerr<<j.y<<endl; d[j.y]=d[x]+1; q.push(j.y); } } } //cerr<<d[t]<<endl; return d[t]; } int dfs(int x,int fl){ if (x==t) return fl; //cerr<<"dfs"<<x<<" "<<fl<<endl; int orz=fl; for (int &j=cur[x]; j<g[x].size(); ++j){ edge &e=g[x][j]; int t=0; if (e.cap&&d[e.y]==d[x]+1&&(t=dfs(e.y,min(fl,e.cap)))){ //cerr<<"init"<<endl; e.cap-=t; g[e.y][e.op].cap+=t; fl-=t; if (!fl) return orz; } } return orz-fl; } int maxflow(){ int ans=0; while (bfs()){ //cerr<<"BFS"<<endl; //for (int i=s; i<=t; ++i) cerr<<d[i]<<" "; //cerr<<endl; //getchar(); ans+=dfs(s,2333333); } //cerr<<"ans"<<ans<<endl; return ans; } int calc(int lim){ //cerr<<"calc"<<lim<<endl; s=0; t=tot*2+1; int bbbb=0; for (int i=s; i<=t; ++i) g[i].clear(); for (int i=2; i<=tot; ++i){ //cerr<<"IIIII"<<i<<endl; if (val[i]>=lim){ ++bbbb; add(s,i*2-1,1); add(i*2,t,1); } add(i*2,i*2-1,23333333); } //cerr<<"___________"<<endl; //cerr<<"tot"<<tot<<endl; for (int i=2; i<=tot; ++i) for (int c=0; c<26; ++c){ if (trans[i][c]){ add(i*2-1,trans[i][c]*2,233333); } } for (int i=2; i<=tot; ++i) if (fa[i]>1) add(fa[i]*2-1,i*2,2333333); return bbbb-maxflow(); } void update(){ for (int i=tot; i>=2; --i) val[fa[i]]=max(val[fa[i]],val[i]); } int n,k; int main(){ scanf("%d%d",&n,&k); scanf("%s",ss+1); vector<int> v; for (int i=1; i<=n; ++i) scanf("%d",&aa[i]),v.push_back(aa[i]); //cerr<<"!!!!!"<<endl; init(); for (int i=1; i<=n; ++i) build(ss,1,i); // for (int i=1; i<=tot; ++i) cerr<<val[i]<<" "; update(); //cerr<<"????"<<endl; //cerr<<"tpt:"<<tot<<endl; sort(v.begin(),v.end()); //for (int i=1; i<=tot; ++i) cerr<<fa[i]<<" "; //cerr<<endl; //for (int i=1; i<=tot; ++i) cerr<<val[i]<<" "; //calc(3); //return 0; int ret=-1; for (int l=0,r=v.size()-1,mid=(l+r)>>1; l<=r; mid=(l+r)>>1) if (calc(v[mid])>=k) ret=v[mid],l=mid+1; else r=mid-1; if (ret==-1) cout<<"NEGATIVE"<<endl; else cout<<ret<<endl; }