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. 03搭建docker私有仓库

    搭建docker私仓,可以使用docker官方提供的registry镜像.该镜像目前有2.0,2.3和2.3.1版本.它只与1.6.0以上版本的docker兼容.搭建私仓的步骤如下: 一:无代理.无认 ...

  2. cPickle对python对象进行序列化,序列化到文件或内存

    pickle模块使用的数据格式是python专用的,并且不同版本不向后兼容,同时也不能被其他语言说识别.要和其他语言交互,可以使用内置的json包 cPickle可以对任意一种类型的python对象进 ...

  3. epoll与fork

    使用epoll时,如果在调用epoll_create之后,调用了fork创建子进程,那么父子进程虽然有各自epoll实例的副本,但是在内核中,它们引用的是同一个实例.子进程向自己的epoll实例添加. ...

  4. HZOJ 走格子

    作者的正解: 对于100%的数据:行动可以分为两种: 1. 步行,花费一个单位的时间移动到4联通的相邻格子中去. 2. 使用传送门,指定一个方向的墙的前面的一个格子,步行至最近的一个墙的面前,使用传送 ...

  5. C++ sort使用两个参数来排序

    排序在编程中经常用到,冒泡法排序时间复杂度高,使用C++库函数sort可以快速排序. 1.必须的头文件#include < algorithm>和using namespace std;  ...

  6. 洛谷P1981 表达式求值 题解 栈/中缀转后缀

    题目链接:https://www.luogu.org/problem/P1981 这道题目就是一道简化的中缀转后缀,因为这里比较简单,只有加号(+)和乘号(*),所以我们只需要开一个存放数值的栈就可以 ...

  7. Python--day26--复习

  8. java List接口中常用类

    Vector:线程安全,但速度慢,已被ArrayList替代. ArrayList:线程不安全,查询速度快. LinkedList:链表结构,增删速度快.取出List集合中元素的方式: get(int ...

  9. UVA 12563 "Jin Ge Jin Qu hao" (背包)

    传送门 debug了好一会,突然发现,输出错了,emmm......... 明天再写debug历程: (PS:ipad debug是真的繁琐) 题意: 题解: 尽管题干中给的 t 的范围很大,但是 t ...

  10. P1054 全组合

    题目描述 给定n,m,按字典序输出所有从1-n里面取出m个数的组合.比如从1-3里面取出2个的组合是: 1 2 1 3 2 3 输入格式 输入两个数n,m.其中 \(0<n<=10,0&l ...