题目链接:https://www.luogu.org/problemnew/show/P2766

题解(大量参考https://blog.csdn.net/ZscDst/article/details/82423342):

第一问,可以用DP求解,用 $f[i]$ 表示以 $a[i]$ 为结尾的最长不减子序列的长度,DP时间复杂度 $O(n^2)$,假设求得长度为 $len$。

第二问我们可以用网络流来求解:

1、由于每个点只能被选一次,所以拆点,控制每个数只能选一次。

2、源点往所有 $f[i]=1$ 的点连一条边权为 $1$ 的边,所有 $f[i]=len$ 的点往汇点连一条边权为 $1$ 的边。

3、如果 j 点是由 i 点转移得到的(即f[i]+1==f[j] && a[i] <= a[j]),那么 i+n 往 j 连一条边权为1的边。

第三问:

$x[1]$ 和 $x[n]$ 可以使用多次,首先 $x[1],x[n]$ 拆出来的两个点之间的容量需要修改。

同时,此题中必然有一条边从源点连向 $x[1]$,所以这条边的容量也要修改。$x[n]$ 不一定是汇点,若 $x[n]$ 是汇点,那么 $x[n]$ 到汇点的边的容量也要修改。

如果重新构图去跑可能会超时,我们知道网络流是可以继续在残量网络中跑的,所以我们直接再添加新边,再继续跑网络流,累加到第二问的答案上,即为第三问的答案。

AC代码:

#include<bits/stdc++.h>
#define I(x) x
#define O(x) (n+x)
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=; int n,x[maxn];
int f[maxn]; struct Edge{
int u,v,c,f;
};
struct Dinic
{
static const int SIZE=*maxn;
int s,t; //源点汇点
vector<Edge> E;
vector<int> G[SIZE];
void init(int l,int r)
{
E.clear();
for(int i=l;i<=r;i++) G[i].clear();
}
void addedge(int from,int to,int cap)
{
E.push_back((Edge){from,to,cap,});
E.push_back((Edge){to,from,,});
G[from].push_back(E.size()-);
G[to].push_back(E.size()-);
}
int dist[SIZE],vis[SIZE];
queue<int> q;
bool bfs() //在残量网络上构造分层图
{
memset(vis,,sizeof(vis));
while(!q.empty()) q.pop();
q.push(s);
dist[s]=;
vis[s]=;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=;i<G[now].size();i++)
{
Edge& e=E[G[now][i]]; int nxt=e.v;
if(!vis[nxt] && e.c>e.f)
{
dist[nxt]=dist[now]+;
q.push(nxt);
vis[nxt]=;
}
}
}
return vis[t];
}
int dfs(int now,int flow)
{
if(now==t || flow==) return flow;
int rest=flow,k;
for(int i=;rest> && i<G[now].size();i++)
{
Edge &e=E[G[now][i]]; int nxt=e.v;
if(e.c>e.f && dist[nxt]==dist[now]+)
{
k=dfs(nxt,min(rest,e.c-e.f));
if(!k) dist[nxt]=; //剪枝,去掉增广完毕的点
e.f+=k; E[G[now][i]^].f-=k;
rest-=k;
}
}
return flow-rest;
}
int mf; //存储最大流
int maxflow()
{
mf=;
int flow=;
while(bfs()) while(flow=dfs(s,INF)) mf+=flow;
return mf;
}
}dinic; int main()
{
cin>>n;
for(int i=;i<=n;i++) scanf("%d",&x[i]); int len=;
dinic.init(dinic.s=,dinic.t=*n+);
for(int i=;i<=n;i++)
{
dinic.addedge(I(i),O(i),); f[i]=;
for(int j=;j<i;j++)
if(x[j]<=x[i]) f[i]=max(f[i],f[j]+);
len=max(len,f[i]); if(f[i]==) dinic.addedge(dinic.s,I(i),);
else
{
for(int j=;j<i;j++)
if(x[j]<=x[i] && f[j]+==f[i]) dinic.addedge(O(j),I(i),);
}
}
cout<<len<<endl; for(int i=;i<=n;i++)
if(f[i]==len) dinic.addedge(O(i),dinic.t,); int ans=dinic.maxflow();
cout<<ans<<endl; dinic.addedge(dinic.s,I(),INF), dinic.addedge(I(),O(),INF);
dinic.addedge(I(n),O(n),INF);
if(f[n]==len) dinic.addedge(O(n),dinic.t,INF); cout<<ans+dinic.maxflow()<<endl;
}

Luogu 2766 - 最长不下降子序列问题 - [LIS问题][DP+网络流]的更多相关文章

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

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

  2. 最长不下降子序列(LIS)

    最长上升子序列.最长不下降子序列,解法差不多,就一点等于不等于的差别,我这里说最长不下降子序列的. 有两种解法. 一种是DP,很容易想到,就这样: REP(i,n) { f[i]=; FOR(j,,i ...

  3. 动态规划——最长不下降子序列(LIS)

    最长不降子序列是这样一个问题: 下面介绍动态规划的做法. 令 dp[i] 表示以 A[i] 结尾的最长不下降序列长度.这样对 A[i] 来说就会有两种可能: 如果存在 A[i] 之前的元素 A[j] ...

  4. 最长不下降子序列(线段树优化dp)

    最长不下降子序列 题目大意: 给定一个长度为 N 的整数序列:A\(_{1}\),A\(_{2}\),⋅⋅⋅,A\(_{N}\). 现在你有一次机会,将其中连续的 K 个数修改成任意一个相同值. 请你 ...

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

    第一问可以直接DP来做,联想上一题,线性规划都可以化为网络流?我们可以借助第一问的DP数组,来建立第二问第三问的网络流图,考虑每一种可能,都是dp数组中满足num[i]>=num[j]& ...

  6. [Swust OJ 585]--倒金字塔(LIS最长不下降子序列)

    题目链接:http://acm.swust.edu.cn/problem/585/ Time limit(ms): 3000 Memory limit(kb): 65535   SWUST国的一支科学 ...

  7. luogu2766 最长不下降子序列问题

    第一问DP水过.dp[i]代表以i结尾的最长不下降子序列长度. 二三问网络流. 第二问是说每个子序列不能重复使用某个数字. 把每个点拆成p(i),q(i).连边. 要是dp[i]=1,连源,p(i) ...

  8. Libre 6005 「网络流 24 题」最长递增子序列 / Luogu 2766 最长递增子序列问题(网络流,最大流)

    Libre 6005 「网络流 24 题」最长递增子序列 / Luogu 2766 最长递增子序列问题(网络流,最大流) Description 问题描述: 给定正整数序列x1,...,xn . (1 ...

  9. Luogu 1020 导弹拦截(动态规划,最长不下降子序列,二分,STL运用,贪心,单调队列)

    Luogu 1020 导弹拦截(动态规划,最长不下降子序列,二分,STL运用,贪心,单调队列) Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺 ...

随机推荐

  1. 更改 Ubuntu默认Python版本的问题

    一般Ubuntu默认版本为2.x,之前运行一些程序,将默认版本修改为3.5,现在想修改为2.7. 之前的方法有些忘记,现在重新记录一下: 1.查看你系统中有哪些Python的二进制文件可供使用, ls ...

  2. Django之分页

    需要知道:每页多少条数据.一共多少条数据.一共需要多少页.每页从哪开始到哪结束 注意问题:1.用户输入页码为非数字.  2.用户输入页码超出页码范围 def books(request): try: ...

  3. HTTP协议08-请求首部字段

    请求首部字段 请求首部字段是从客户端往服务器端发送请求报文中所使用的字段,用于补充请求的附加信息.客户端信息,对响应内容相关的优先级等内容 1)Accept 通知服务器,用户代理能够处理的媒体类型及媒 ...

  4. 【原创】大数据基础之ElasticSearch(4)es数据导入过程

    1 准备analyzer 内置analyzer 参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis- ...

  5. drf版本控制 和django缓存,跨域问题,

    drf版本控制 基于url的get传参方式 REST_FRAMEWORK={ # "DEFAULT_AUTHENTICATION_CLASSES":["app01.aut ...

  6. 初学python之路-day01

    第一天学习python,先了解到了进制之间的转换关系. 如二进制与十进制的转换,如1111转成十进制为15,1111从左向右可看出2^3+2^2+2^1+2^0为8+4+2+1=15.记住前8位1的二 ...

  7. JDBC 返回主键

    转载至:https://www.liyongzhen.com/ 上一节课里我们学习通过PreparedStatement对象执行带参数的查询SQL和修改SQL. 这节课我们学习使用 PreparedS ...

  8. Elasticsearch先聚合再按时间排序返回需要的字段

    { "query": { "bool": { "must": [ { "term": { "area_code ...

  9. 安装Visual C++ 6.0后报错:应用程序无法正常启动(0xc0000142)

    最近在安装Visual C++ 6.0时,本来想用个中文版的,结果刚安装好就报了这个错误 百度后发现是由于汉化后的Visual C++ 6.0与win10不兼容造成的 解决办法就是替换程序,把中文版的 ...

  10. Beta(7/7)

    鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...