题目大意:给定正整数序列x1,...,xn 。(1)计算其最长不下降子序列的长度s。(不一定是否连续)(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。(序列内每一个元素不可重复)(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。

关键词:不相交路径,拆点

(1)DP经典题LIS。令原序列为A[i],DP[i]表示以i为结尾的不下降子序列长度最长为多少。

(2)

不相交路径:想象有一个流把一个子序列内的每一个元素都串了起来。后一个元素与前一个元素可连接的标志是DP[j]=DP[i]+1且A[i]<=A[j]。

拆点:每个元素只能访问一次,因此把一个元素拆成一条容量为1的边,两元素若可连接,则将前元素的to点连后元素的from点。为了从头开始,从尾结束,因此将S与DP[i]=1的元素边的from点连,DP[i]=S的元素边的to点与T连。然后求最大流即可。

(3)将与1元素边的from点和与n元素边的to节点相连的正向边容量设为∞,然后求最大流。

#include <cstdio>
#include <cstring>
#include <cassert>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std; #define LOOP(i,n) for(int i=1; i<=n; i++)
const int MAX_NODE = , MAX_EDGE = MAX_NODE*MAX_NODE, INF = 0x3f3f3f3f;//注意MAX_NODE=500*2
int A[MAX_NODE], DP[MAX_NODE];
int Tot, MaxLen, Sid, Tid;
//#define test struct Dinic
{
struct Edge;
struct Node; struct Node
{
int Id, Level;
Edge* Head;
Edge *DfsFrom;
}; struct Edge
{
int Cap, OrgCap;
Node *From, *To;
Edge *Next, *Rev;
Edge(int cap, Node *from, Node *to, Edge *next) :Cap(cap), OrgCap(cap), From(from), To(to), Next(next) {}
}; Node _nodes[MAX_NODE];
Edge *_edges[MAX_EDGE];
int _vCount, _eCount;
Node *Start, *Target; void Init(int Sid, int Tid, int vCount)
{
memset(_nodes, , sizeof(_nodes));
memset(_edges, , sizeof(_edges));
_eCount = ;
Start = Sid + _nodes;
Target = Tid + _nodes;
_vCount = vCount;
} void Recover()
{
LOOP(i, _eCount)
_edges[i]->Cap = _edges[i]->OrgCap;
} Edge* AddEdge(Node *from, Node *to, int cap)
{
Edge *e = _edges[++_eCount] = new Edge(cap, from, to, from->Head);
e->From->Head = e;
return e;
} void Build(int uId, int vId, int eCap)
{
Node *u = uId + _nodes, *v = vId + _nodes;
u->Id = uId;
v->Id = vId;
Edge *edge1 = AddEdge(u, v, eCap), *edge2 = AddEdge(v, u, );
edge1->Rev = edge2;
edge2->Rev = edge1;
} bool Bfs()
{
for (int i = ; i <= _vCount; i++)
_nodes[i].Level = ;
static queue<Node*> q;
Start->Level = ;
q.push(Start);
while (!q.empty())
{
Node *u = q.front();
q.pop();
for (Edge *e = u->Head; e; e = e->Next)
{
assert(e->Cap >= );
if (!e->To->Level && e->Cap)
{
e->To->Level = u->Level + ;
q.push(e->To);
}
}
}
return Target->Level;
} int Dfs(Node *cur, int limit)
{
if (cur == Target)
return limit;
if (limit == )
return ;
int curTake = ;
for (Edge *e = cur->DfsFrom; e; cur->DfsFrom = e = e->Next)
{
if (e->To->Level == cur->Level + && e->Cap)
{
int nextTake = Dfs(e->To, min(limit - curTake, e->Cap));
e->Cap -= nextTake;
e->Rev->Cap += nextTake;
curTake += nextTake;
}
if (limit - curTake == )
break;
}
return curTake;
} int Proceed()
{
int ans = ;
while (Bfs())
{
for (int i = ; i <= _vCount; i++)
_nodes[i].DfsFrom = _nodes[i].Head;
ans += Dfs(Start, INF);
}
return ans;
}
}g; void P1()
{
LOOP(j, Tot)
{
int maxLen = ;
LOOP(i, j - )
if (A[i] <= A[j])
maxLen = max(maxLen, DP[i]);
DP[j] = maxLen + ;
}
MaxLen = ;
LOOP(i, Tot)
MaxLen = max(MaxLen, DP[i]);
printf("%d\n", MaxLen);
} void P2()
{
Sid = Tot * + , Tid = Tot * + ;
g.Init(Sid, Tid, Tid);
LOOP(i, Tot)
g.Build(i, i + Tot, );
LOOP(i, Tot)
{
if (DP[i] == )
g.Build(Sid, i, );
if (DP[i] == MaxLen)
g.Build(i + Tot, Tid, );
else
for (int j = i + ; j <= Tot; j++)
if (DP[j] == DP[i] + && A[j] >= A[i])
g.Build(i + Tot, j, );
}
printf("%d\n", g.Proceed());
} void P3()
{
for (Dinic::Edge* e = g._nodes[].Head; e; e = e->Next)
{
if (e->To->Id == + Tot)
e->OrgCap = INF;
else if (e->To == g.Start)
e->Rev->OrgCap = INF;
}
for (Dinic::Edge *e = g._nodes[Tot * ].Head; e; e = e->Next)
{
if (e->To->Id == Tot)
e->Rev->OrgCap = INF;
else if (e->To == g.Target)
e->OrgCap = INF;
}
g.Recover();
printf("%d\n", g.Proceed());
} int main()
{
#ifdef _DEBUG
freopen("c:\\noi\\source\\input.txt", "r", stdin);
#endif
scanf("%d", &Tot);
LOOP(i, Tot)
scanf("%d", i + A);
P1();
P2();
P3();
return ;
}

注意:

1.本题是“不下降”,而不是“上升”。因此(1)题DP时应该为A[i]<=A[j],而不是A[i]<A[j]。

2.(2)问不要忘了判断元素可连接的标志还有A[i]<=A[j]。

3.(3)题改容量时注意改的到底时正向边的容量还是反向边的容量,要清楚。

luogu2766 最长不下降子序列问题 DP 网络流的更多相关文章

  1. 最长不下降子序列//序列dp

    最长不下降子序列 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 求最长不下降子序列的长度 输入格式 第一行为n,表示n个数第二行n个数 输出格式 最长不下降 ...

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

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

  3. Codeforces Round #323 (Div. 2) Once Again... CodeForces - 582B 最长非下降子序列【dp】(不明白)

    B. Once Again... time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  4. HDU 1087 最长不下降子序列 LIS DP

    Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. May ...

  5. SPOJ 4053 - Card Sorting 最长不下降子序列

    我们的男主现在手中有n*c张牌,其中有c(<=4)种颜色,每种颜色有n(<=100)张,现在他要排序,首先把相同的颜色的牌放在一起,颜色相同的按照序号从小到大排序.现在他想要让牌的移动次数 ...

  6. 【DP】最长不下降子序列问题(二分)

    Description 给你一个长度为n的整数序列,按从左往右的顺序选择尽量多的数字并且满足这些数字不下降. Thinking 朴素dp算法:F[i]表示到第i位为止的最长不下降子序列长度 F[i]= ...

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

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

  8. 「10.19」最长不下降子序列(DP)·完全背包问题(spfa优化DP)·最近公共祖先(线段树+DFS序)

    我又被虐了... A. 最长不下降子序列 考场打的错解,成功调了两个半小时还是没A, 事实上和正解的思路很近了,只是没有想到直接将前$D$个及后$D$个直接提出来 确实当时思路有些紊乱,打的时候只是将 ...

  9. NOIP 2004 T3 合唱队形(DP、最长上升/下降子序列)

    链接:https://ac.nowcoder.com/acm/contest/1082/C来源:牛客网 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队 ...

随机推荐

  1. Spring Boot (9) mybatis全注解化

    ORM对比图 框架对比 Spring JDBC Spring Data Jpa Mybatis 性能 性能最好 性能最差 居中 代码量 多 少 多 学习成本 低 高 居中 推荐指数 ❤❤❤ ❤❤❤❤❤ ...

  2. 网上干货 ElasticSearch详解与优化设计

    https://blog.csdn.net/joez/article/details/52171199?locationNum=3&fps=1 分析得很好,需要仔细阅读 问题遗留点: Fiel ...

  3. div自动适应浏览器窗口水平和垂直居中

    html <body> <div id="centerDiv">自动适应水平和垂直居中</div> </body> css ;;} ...

  4. Android 侦听应用(Package)变化的方法侦听广播

    应用的状态变化,包括安装.卸载.更新,是android系统上重要的事件.如何侦听到?有两种方法,一是通过侦听广播,一是实现PackageMonitor. 侦听广播   当Package状态发生变化时, ...

  5. python爬虫:找房助手V1.0-爬取58同城租房信息

    1.用于爬取58上的租房信息,限成都,其他地方的,可以把网址改改: 2.这个爬虫有一点问题,就是没用多线程,因为我用了之后总是会报: 'module' object has no attribute ...

  6. C++多个文本读取问题

    同时使用两个 ifstream和 freopen 第二个就会失去效用,不知道错在了哪里! 1. 使用freopen打开: bool CPicToolsDlg::readTxt2Seq( std::st ...

  7. Vue: axios 请求封装及设置默认域名前缀 (for Vue 2.0)

    1. 实现效果 以get方法向http://192.168.32.12:8080/users 发起请求.获取数据并进行处理 this.apiGet('/users', {}) .then((res) ...

  8. tomcat多实例的部署

    解压部署tomcat程序创建2个实例的工作目录mkdir -p /usr/local/tomcat8_instance/tomcat1mkdir -p /usr/local/tomcat8_insta ...

  9. 【转载】java实现HTTP请求的三种方式

    目前JAVA实现HTTP请求的方法用的最多的有两种:一种是通过HTTPClient这种第三方的开源框架去实现.HTTPClient对HTTP的封装性比较不错,通过它基本上能够满足我们大部分的需求,Ht ...

  10. php第四节课

    对象 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...