luogu2766 最长不下降子序列问题 DP 网络流
题目大意:给定正整数序列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 网络流的更多相关文章
- 最长不下降子序列//序列dp
最长不下降子序列 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 求最长不下降子序列的长度 输入格式 第一行为n,表示n个数第二行n个数 输出格式 最长不下降 ...
- luogu2766 最长不下降子序列问题
第一问DP水过.dp[i]代表以i结尾的最长不下降子序列长度. 二三问网络流. 第二问是说每个子序列不能重复使用某个数字. 把每个点拆成p(i),q(i).连边. 要是dp[i]=1,连源,p(i) ...
- 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 ...
- HDU 1087 最长不下降子序列 LIS DP
Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. May ...
- SPOJ 4053 - Card Sorting 最长不下降子序列
我们的男主现在手中有n*c张牌,其中有c(<=4)种颜色,每种颜色有n(<=100)张,现在他要排序,首先把相同的颜色的牌放在一起,颜色相同的按照序号从小到大排序.现在他想要让牌的移动次数 ...
- 【DP】最长不下降子序列问题(二分)
Description 给你一个长度为n的整数序列,按从左往右的顺序选择尽量多的数字并且满足这些数字不下降. Thinking 朴素dp算法:F[i]表示到第i位为止的最长不下降子序列长度 F[i]= ...
- 洛谷 P2766 最长不下降子序列问【dp+最大流】
死于开小数组的WA?! 第一问n方dp瞎搞一下就成,f[i]记录以i结尾的最长不下降子序列.记答案为mx 第二问网络流,拆点限制流量,s向所有f[i]为1的点建(s,i,1),所有f[i]为mx(i+ ...
- 「10.19」最长不下降子序列(DP)·完全背包问题(spfa优化DP)·最近公共祖先(线段树+DFS序)
我又被虐了... A. 最长不下降子序列 考场打的错解,成功调了两个半小时还是没A, 事实上和正解的思路很近了,只是没有想到直接将前$D$个及后$D$个直接提出来 确实当时思路有些紊乱,打的时候只是将 ...
- NOIP 2004 T3 合唱队形(DP、最长上升/下降子序列)
链接:https://ac.nowcoder.com/acm/contest/1082/C来源:牛客网 题目描述 N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队 ...
随机推荐
- 每日算法——新型在线LCA
在线LCA一般大家都会用倍增吧,时间复杂度O(nlogn),空间复杂度O(nlogn),都是非常严格的复杂度限制,并且各种边界处理比较麻烦,有没有更快更好的办法呢? 我们发现,在树链剖分时,我们不经意 ...
- 如何正确从windows系统(自己电脑)远程访问Linux系统(他人电脑)的mysql数据库(图文详解)
这里,需要Linux系统开了root用户,我这给root用户密码为root. 同时,在mysql -uroot -proot执行进去之后 update user setHost='%' whe ...
- 微信图片不可显示java解决方法
先看知乎:https://www.zhihu.com/question/35044484 场景: 微信上传了图片素材,返回了图片url,然后不能在img标签中正常显示. 原因是微信做了图片防盗连接. ...
- SQL server高级语法
1. 公共表达式CTE 公用表表达式 (CTE) 具有一个重要的优点,那就是能够引用其自身,从而创建递归 CTE.递归 CTE 是一个重复执行初始 CTE 以返回数据子集直到获取完整结果集的公用表表达 ...
- 图像局部显著性—点特征(GLOH)
基于古老的Marr视觉理论,视觉识别和场景重建的基础即第一阶段为局部显著性探测.探测到的主要特征为直觉上可刺激底层视觉的局部显著性--特征点.特征线.特征块. 相关介绍:局部特征显著性-点特征(SIF ...
- SLAM:飞行机器人的参数解析-分类
在水电站存在的山区,公路运输效率极低,盘山公路绕行消耗大量时间,使用飞行机器人进行运输是合适的选择. 实现一位长辈在山区飞行的愿望,任重而道远 常见飞行机器人的参数解析:解读飞行机器人的基本类型及技术 ...
- 浅谈Overload和Override的区别
如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding).如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Over ...
- js 习题
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- python write和writelines的区别
file.write(str)的参数是一个字符串,就是你要写入文件的内容.file.writelines(sequence)的参数是序列,比如列表,它会迭代帮你写入文件. 下面两种方式写入文件的效果是 ...
- luogu P4719 【模板】动态 DP 矩阵乘法 + LCT
方法二:LCT+矩阵乘法 上文中,我们用线段树来维护重链上的各种矩阵转移. 第二种方法是将树链剖分替换为动态树. 我们知道,矩阵乘法 $\begin{bmatrix} F_{u,0} & F_ ...