[网络流24题]最长递增子序列问题
Description
给定正整数序列$x_1,x_2,...,x_n$.
$1.$计算其最长递增子序列的长度$L$。
$2.$计算从给定的序列中最多可取出多少个长度为$L$的递增子序列。
$3.$如果允许在取出的序列中多次使用$x_1,x_n$,则从给定序列中最多可取出多少个长度为$L$的递增子序列。
Input
第$1$行有$1$个正整数$n$,表示给定序列的长度。
接下来的$1$行有$n$个正整数$x_1,x_2,...,x_n$。
Output
第$1$行是最长递增子序列的长度$L$。
第$2$行是可取出的长度为$L$的递增子序列个数。
第$3$行是允许在取出的序列中多次使用$x_1,x_n$时可取出的长度为$L$的递增子序列个数。
Sample Input
4
3 6 2 5
Sample Output
2
2
3
HINT
$n<500$
Solution
- 第一问:
最简单的$LIS$的$DP$.
- 第二问:
将每个数$a_i$进行拆点:$x_i,y_i$,中间连一条边限制其流量(即使用次数).
从$x_i$向$y_i$连一条容量为$1$的有向边.
如果$f[i]=L$,从$s$向$x_i$连一条容量为$1$的有向边.
如果$f[i]=1$,从$y_i$向$t$连一条容量为$1$的有向边.
如果$i<j,a_i<a_j,f[i]+1=f[j]$,从$y_j$向$x_i$连一条容量为$1$的有向边.
求最大流.
- 第三问:
将$(x_1,y_1),(x_n,y_n),(x_1,t),(s,x_n)$的值改成$+\infty$.
求最大流.
#include<cmath> #include<ctime> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 500 #define M 500000 using namespace std; struct graph{ int nxt,to,f; }e[M]; int a[N],f[N],g[N<<1],dep[N<<1],n,m,s,t,cnt=1; queue<int> q; inline void addedge(int x,int y,int f){ e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f; } inline void adde(int x,int y,int f){ addedge(x,y,f);addedge(y,x,0); } inline bool bfs(int u){ memset(dep,0,sizeof(dep)); q.push(u);dep[u]=1; while(!q.empty()){ u=q.front();q.pop(); for(int i=g[u];i;i=e[i].nxt) if(e[i].f>0&&!dep[e[i].to]){ q.push(e[i].to); dep[e[i].to]=dep[u]+1; } } return dep[t]; } inline int dfs(int u,int f){ int ret=0; if(u==t) return f; for(int i=g[u],d;i&&f;i=e[i].nxt) if(e[i].f>0&&dep[e[i].to]>dep[u]){ d=dfs(e[i].to,min(f,e[i].f)); ret+=d;f-=d;e[i].f-=d;e[i^1].f+=d; } return ret; } inline int dinic(){ int ret=0; while(true){ if(!bfs(s)) return ret; ret+=dfs(s,M); } } inline void Aireen(){ scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]); for(int i=1;i<=n;++i){ f[i]=1; for(int j=1;j<i;++j) if(a[j]<a[i]) f[i]=max(f[i],f[j]+1); m=max(m,f[i]); } printf("%d\n",m); s=(n<<1)+1;t=s+1; for(int i=1;i<=n;++i){ adde(i,i+n,1); if(f[i]==1) adde(i+n,t,1); if(f[i]==m) adde(s,i,1); for(int j=1;j<i;++j) if(a[j]<a[i]&&f[j]+1==f[i]) adde(i+n,j,1); } printf("%d\n",dinic()); cnt=1;memset(g,0,sizeof(g)); for(int i=1,c,d,k;i<=n;++i){ c=d=k=1; if(i==1) c=k=M; if(i==n) d=k=M; adde(i,i+n,k); if(f[i]==1) adde(i+n,t,c); if(f[i]==m) adde(s,i,d); for(int j=1;j<i;++j) if(a[j]<a[i]&&f[j]+1==f[i]) adde(i+n,j,1); } printf("%d\n",dinic()); } int main(){ freopen("alis.in","r",stdin); freopen("alis.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }