最长不下降子序列问题

sshwy

2019-03-03 09:11:34

Personal

# 题意 对一个序列做3个统计: - 最长不下降子序列的长度$k$ - 每个数用一次,可以不用,最多能组成多少个长度为$k$的不下降子序列 - 在$Subtask2$的基础上,允许第一个数和最后一个数多次使用,求最多能组成多少个长度为$k$的不下降子序列 $n\leq 500$. <!--more--> # Subtask1 $O(n^2)$暴力DP即可,定义$f[i]​$表示以$a_i​$开头的最长不下降子序列的长度 $$ f[i]=\max_{j=i+1}^n\{f[j]+1\}. $$ # Subtask2 构造网络流模型如下(c表示边的容量) - 每个数只能使用一次$\Leftrightarrow $拆点$u_{in},u_{out}$,并添加$c(u_{in},u_{out})=1$. - $f[u]=k\Leftrightarrow c(s,u_{in})=1$. - $f[u]=1\Leftrightarrow c(u_{out},t)=1$. - $u<v,a_u\leq a_v,f[u]=f[v]+1\Leftrightarrow c(u_{out},v_{in})=1$. 跑一遍最大流即可 # Subtask3 在$Subtask2$的基础上修改(或者直接加边)如下 - $c(n_{in},n_{out})=INF,c(n_{out},t)=INF$. - $f[1]=k\Leftrightarrow c(s,1_{in})=INF,c(1_{in},1_{out})=INF$. 再跑一遍最大流即可 # 代码 ```cpp #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=1200,M=300000,INF=0x3f3f3f3f; int n,m,s,t,k; int a[N],f[N]; struct qxx{int nex,t,v;}; qxx e[M]; int cnt=1,h[N],cur[N]; void add_path(int f,int t,int v){e[++cnt]=(qxx){h[f],t,v},h[f]=cnt;} void add_flow(int f,int t,int v){add_path(f,t,v),add_path(t,f,0);} int rk[N]; bool bfs(){ queue<int> q; memset(rk,0,sizeof(rk)); memcpy(cur,h,sizeof(cur)); q.push(s),rk[s]=1; while(q.size()){ int u=q.front();q.pop(); for(int i=h[u];i;i=e[i].nex){const int &v=e[i].t,&w=e[i].v; if(w&&!rk[v])rk[v]=rk[u]+1,q.push(v); } } return rk[t]; } int dinic(int u,int flow){ if(u==t)return flow; int x,rest=flow; for(int i=cur[u];i&&rest;i=e[i].nex){const int &v=e[i].t,&w=e[i].v; if(!w||rk[v]!=rk[u]+1)continue; x=dinic(v,min(w,rest)); if(x)e[i].v-=x,e[i^1].v+=x,rest-=x; else rk[v]=0; if(!rest)cur[u]=i; } if(rest)cur[u]=0; return flow-rest; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); //sbt1 for(int i=n;i>=1;i--){ for(int j=i+1;j<=n;j++)if(a[i]<=a[j])f[i]=max(f[i],f[j]); k=max(k,++f[i]); } printf("%d\n",k); //sbt2 s=0,t=n+n+2; for(int i=1;i<=n;i++){ add_flow(i<<1,i<<1|1,1); if(f[i]==k)add_flow(s,i<<1,1); if(f[i]==1)add_flow(i<<1|1,t,1);//不要随便加else for(int j=i+1;j<=n;j++)if(a[i]<=a[j]&&f[i]==f[j]+1)add_flow(i<<1|1,j<<1,1); } int maxflow=0; while(bfs())for(int i;i=dinic(s,INF);)maxflow+=i; printf("%d\n",maxflow); //sbt3 add_flow(n<<1,n<<1|1,INF);add_flow(n<<1|1,t,INF); if(f[1]==k){add_flow(s,1<<1,INF);add_flow(1<<1,1<<1|1,INF);} while(bfs())for(int i;i=dinic(s,INF);)maxflow+=i; printf("%d\n",maxflow); return 0; } ```