P2766 最长不下降子序列问题

考虑我们是如何\(dp\)这个\(LIS\)的。

我们是倒着推,设置\(dp(i)\)代表以\(i\)为起点的\(LIS\)是多少。转移太显然了

\[dp(i)=max\{dp(j)\}+1,data[i]\le data[j]
\]

想一想一个合法的\(LIS\)方案代表着什么,代表着它是由这个式子一个一个推出来的。

考虑一个数字只能用一次,那么我们直接拆成两个点\(v_0,v_1\)分别代表一个数字的入度和出度,连一条\(v_1v_2,cap=1\)的边。这样就模拟了一个数字可以被前面多个都相中但是只能往后面相中一个的要求。

考虑如何构造方案,这个东西是个灵感,就是还原\(dp\)的过程,这样就可以得到合法方案。

模型这样建立

\[(i_0,i_1,1)
\\
(S,i_0,inf),dp(i)=1
\\
(i_1,T,inf),dp(k)=ans
\]

这样就好了。

实际上,这样建模体现了"且"的关系,这种建模方式在以后可能大有用处。

#include<bits/stdc++.h>

using namespace std;typedef long long ll;
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;++t)
#define ERP(t,a) for(register int t=head[a];t!=-1;t=e[t].nx)
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
#define pushup(pos) (seg[pos]=seg[pos<<1]+seg[pos<<1|1])
TMP inline ccf qr(ccf b){
register char c=getchar();register int q=1;register ccf x=0;
while(c<48||c>57)q=c==45?-1:q,c=getchar();
while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
return q==-1?-x:x;}
TMP inline ccf Max(ccf a,ccf b){return a<b?b:a;}
TMP inline ccf Min(ccf a,ccf b){return a<b?a:b;}
TMP inline ccf Max(ccf a,ccf b,ccf c){return Max(a,Max(b,c));}
TMP inline ccf Min(ccf a,ccf b,ccf c){return Min(a,Min(b,c));}
TMP inline void READ(ccf* _arr,int _n){RP(t,1,_n)_arr[t]=qr((ccf)1);}
//----------------------template&IO--------------------------- const int maxn=5e2+15;
const int maxm=maxn<<3;
int dp[maxn];
int data[maxn];
const int inf=0x3f3f3f3f;
int n,S,T;
struct E{
int to,w,nx;
}e[maxm<<1],tmp[maxm<<1];
int cnt(-1);
int head[maxm];
int id[maxn][2];
int sz;
int ans1,ans2,ans3;
int d[maxm];
int cur[maxm]; inline void add(int fr,int to,int w,bool f){
e[++cnt]=(E){to,w,head[fr]};head[fr]=cnt;
if(f) add(to,fr,0,0);
} queue < int > q;
inline bool bfs(){
while(not q.empty()) q.pop();
RP(t,1,sz) cur[t]=head[t],d[t]=inf+1;
d[S]=1;q.push(S);
while(not q.empty()){
register int now=q.front();q.pop();
if(now==T) break;
ERP(t,now){
if(d[e[t].to]>d[now]+1&&e[t].w>0){
d[e[t].to]=d[now]+1;
q.push(e[t].to);
}
}
}
return d[T]<inf;
} int dfs(int now,int fl){
if(now==T||!fl) return fl;
register int ret=0;
for(register int t=cur[now],en;t!=-1;t=e[t].nx){
cur[now]=t;
if(d[e[t].to]==d[now]+1){
en=dfs(e[t].to,Min(fl,e[t].w));
if(en){e[t].w-=en;e[t^1].w+=en;fl-=en;ret+=en;}
if(not fl)break;
}
}return ret;
} inline void dinic(int& ret){while(bfs()) ret+=dfs(S,inf);} int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
memset(head,-1,sizeof head);
n=qr(1);
READ(data,n);
RP(t,1,n) dp[t]=1;ans1=1;
DRP(t,n,1) RP(i,t+1,n) if(data[t]<=data[i]) ans1=Max((dp[t]=Max(dp[t],dp[i]+1)),ans1);
S=++sz;T=++sz;
DRP(t,n,1){
id[t][0]=++sz;id[t][1]=++sz;
add(id[t][0],id[t][1],1,1);
if(dp[t]==1){add(id[t][1],T,inf,1);}
if(dp[t]==ans1){add(S,id[t][0],inf,1);}
RP(i,t+1,n) if(data[i]>=data[t]&&dp[i]+1==dp[t]) add(id[t][1],id[i][0],1,1);
}
RP(t,0,cnt) tmp[t]=e[t];
dinic(ans2);
RP(t,0,cnt) e[t]=tmp[t];
add(id[1][0],id[1][1],inf,1);
add(id[n][0],id[n][1],inf,1);
dinic(ans3);
if(ans1==1) ans2=ans3=n;
printf("%d\n%d\n%d\n",ans1,ans2,ans3);
return 0;
}

[**P2766** 最长不下降子序列问题](https://www.luogu.org/problemnew/show/P2766)的更多相关文章

  1. P2766 最长不下降子序列问题 网络流

    link:https://www.luogu.org/problemnew/show/P2766 题意 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的 ...

  2. 【24题】P2766最长不下降子序列问题

    网络流二十四题 网络流是个好东西,希望我也会. 网络流?\(orz\ zsy!!!!!\) P2766 最长不下降子序列问题 考虑我们是如何\(dp\)这个\(LIS\)的. 我们是倒着推,设置\(d ...

  3. P2766 最长不下降子序列问题 网络流重温

    P2766 最长不下降子序列问题 这个题目还是比较简单的,第一问就是LIS 第二问和第三问都是网络流. 第二问要怎么用网络流写呢,首先,每一个只能用一次,所以要拆点. 其次,我们求的是长度为s的不下降 ...

  4. 网络流 之 P2766 最长不下降子序列问题

    题目描述 «问题描述: 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次 ...

  5. 【题解】Luogu P2766 最长不下降子序列问题

    原题传送门 实际还是比较套路的建图 先暴力dp一下反正数据很小 第一小问的答案即珂以求出数列的最长不下降子序列的长度s 考虑第二问如何做: 将每个点拆点 从前向后连一条流量为1的边 如果以它为终点的最 ...

  6. P2766 最长不下降子序列问题

    题目描述 «问题描述: 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次 ...

  7. 洛谷P2766 最长不下降子序列问题(最大流)

    传送门 第一问直接$dp$解决,求出$len$ 然后用$f[i]$表示以$i$为结尾的最长不下降子序列长度,把每一个点拆成$A_i,B_i$两个点,然后从$A_i$向$B_i$连容量为$1$的边 然后 ...

  8. 【Luogu】P2766最长不下降子序列问题(暴力网络流)

    题目链接 水题qwq,数据都那么水. 我要是出数据的人我就卡$n^3$建图. qwq. 然而这么水的题我!居!然!没!有!1!A!!还!提!交!了!五!遍!!! md从现在开始要锻炼1A率了 看我从今 ...

  9. 洛谷 P2766 最长不下降子序列问【dp+最大流】

    死于开小数组的WA?! 第一问n方dp瞎搞一下就成,f[i]记录以i结尾的最长不下降子序列.记答案为mx 第二问网络流,拆点限制流量,s向所有f[i]为1的点建(s,i,1),所有f[i]为mx(i+ ...

随机推荐

  1. SDUT-2054_数据结构实验之链表九:双向链表

    数据结构实验之链表九:双向链表 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 学会了单向链表,我们又多了一种解决问题的 ...

  2. hdu 3662 3D Convex Hull

    Problem - 3662 题意很简单,构造三维凸包,求凸包有多少个面. 代码如下: #include <cstdio> #include <iostream> #inclu ...

  3. MongonDB指令汇总

    MongoDB特点使用不存在的对象,就等于你在创建这个对象(库,表,记录) MongoDB服务器/客户端相关 (记得把配置环境变量bin,MongonDB安装后bin在C盘的programfile-- ...

  4. 初次使用pycharm 的interpreter option为空解决办法。

    第一步:进入Setting. 第二步:进入Project中的Project Interpreter.选择添加即可.

  5. Mysql怎样控制replace替换的次数?

    我想把“ABC是ABC”替换成“123是ABC”,也就是找出第一个ABC替换成123,MYSQL命令应该怎么写? UPDATE data SET body=REPLACE(body, 'ABC', ' ...

  6. HDU 1540 Tunnel Warfare (线段树)

    Tunnel Warfare Problem Description During the War of Resistance Against Japan, tunnel warfare was ca ...

  7. MVC3 学习笔记 之(ajax表单)

    mvc 提供了一种ajax提交表单的方式.与普通表单不同的是,它是一个异步表单. 在开始使用之前,需要引用以下文件: <script src="@Url.Content("~ ...

  8. Less 语法快速入门

    Less 语法快速入门 Less 是一门 CSS 预处理语言其可以运行在 Node 或浏览器端. 它将传统的 css 样式结构单一的排版顺序进行了优化,让我们可以通过层级嵌套的方式将 css 类名与H ...

  9. 2018-8-10-win10-uwp-win2d-离屏渲染

    title author date CreateTime categories win10 uwp win2d 离屏渲染 lindexi 2018-08-10 19:17:19 +0800 2018- ...

  10. Shave Beaver! CodeForces - 331B2 (线段树)

    题面 The Smart Beaver has recently designed and built an innovative nanotechnologic all-purpose beaver ...