#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; }