一看上去就是一个二合一的题。那么先解决第一部分求最优路线(及所有可能在最优路线上的线段)。

  由于不能往下走,可以以y坐标作为阶段。对于y坐标不同的点,我们将可以直接到达的两点连边,显然这样的边的个数是线性的。如果是右上方向那么横纵坐标差相等,左上则和相等,可以直接排序搞定。

  y坐标相同的点(下称一排),如果某个靠左的点向靠右的点转移,那么这个靠右的点的左边所有点都可以走到。可以先将这一排点用之前的点更新完毕,求出某个点不往左右走的最大值,然后用左边的更新右边,右边的更新左边,每次记录一下最大值就是线性的了。于是整个dp一发就好了。

  打印任意一种方案很简单。至于所有方案的路径并,可以把之前求出的“某个点不往左右走能得到的最大值”记录下来。从后往前,对于每一排,先找出“哪些点可以作为最优方案中该排最后一个到达的点”。然后再根据“某个点不往左右走能得到的最大值”找出“哪些点可以作为最优方案中该排第一个到达的点”,具体做法仍然可以先看左边再看右边。而根据这些点上一次的转移,就可以知道哪些线段可以在最优方案内,并且可以标记上之前的“哪些点可以作为最优方案中该排最后一个到达的点”,总的仍是线性。

  做完之后进入第二部分。这部分比较明显,就是多源多汇的上下界最小流。新建一个超源超汇跑一发就做完了。开始跑了一个啥都不是的玩意拿了65分,数据水到一个境界了。

  似乎不是很难。然而……太码农了……

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 50010
#define S 50001
#define T 50002
#define SS 50003
#define ST 50004
int n,from[N][],f[N],g[N],h[N],ans[N],pre[N],t=-;
int p[N],cur[N],d[N],q[N],degree[N],tot=;
struct data{int to,nxt,cap,flow;
}edge[N<<];
bool flag[N],tagend[N],tagstart[N];
struct point{int x,y,i,j;
}a[N];
void addedge(int x,int y,int z)
{
t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=,p[x]=t;
t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=,edge[t].flow=,p[y]=t;
}
bool cmp(const point&a,const point&b)
{
return a.y<b.y||a.y==b.y&&a.x<b.x;
}
bool cmp2(const point&a,const point&b)
{
return a.y-a.x<b.y-b.x||a.y-a.x==b.y-b.x&&a.y<b.y;
}
bool cmp3(const point&a,const point&b)
{
return a.x+a.y<b.x+b.y||a.x+a.y==b.x+b.y&&a.y<b.y;
}
bool cmp4(const point&a,const point&b)
{
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
void print(int x)
{
if (x==) return;
if (a[pre[x]].y==a[x].y)
{
print(pre[pre[x]]);
if (pre[x]>x)
{
printf("%d ",a[pre[x]].j);
int i=pre[x];
while (a[i+].y==a[i].y) i++,printf("%d ",a[i].j);
for (i=pre[x]-;i>=x;i--) printf("%d ",a[i].j);
}
else
{
printf("%d ",a[pre[x]].j);
int i=pre[x];
while (a[i-].y==a[i].y) i--,printf("%d ",a[i].j);
for (i=pre[x]+;i<=x;i++) printf("%d ",a[i].j);
}
}
else
{
print(pre[x]);
printf("%d ",a[x].j);
}
}
bool bfs(int s,int t)
{
memset(d,,sizeof(d));d[s]=;
int head=,tail=;q[]=s;
do
{
int x=q[++head];
for (int i=p[x];~i;i=edge[i].nxt)
if (d[edge[i].to]==-&&edge[i].flow<edge[i].cap)
{
d[edge[i].to]=d[x]+;
q[++tail]=edge[i].to;
}
}while (head<tail);
return ~d[t];
}
int work(int k,int f,int t)
{
if (k==t) return f;
int used=;
for (int i=cur[k];~i;i=edge[i].nxt)
if (d[k]+==d[edge[i].to])
{
int w=work(edge[i].to,min(f-used,edge[i].cap-edge[i].flow),t);
edge[i].flow+=w,edge[i^].flow-=w;
if (edge[i].flow<edge[i].cap) cur[k]=i;
used+=w;if (used==f) return f;
}
if (used==) d[k]=-;
return used;
}
void dinic(int s,int t)
{
while (bfs(s,t))
{
memcpy(cur,p,sizeof(p));
tot+=work(s,N,t);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4200.in","r",stdin);
freopen("bzoj4200.out","w",stdout);
const char LL[]="%I64d";
#else
const char LL[]="%lld";
#endif
n=read();
for (int i=;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].j=i;
sort(a+,a+n+,cmp);
for (int i=;i<=n;i++) a[i].i=i;
for (int i=;i<=n;i++) from[i][]=from[i][]=from[i][]=;
sort(a,a+n+,cmp2);
for (int i=;i<=n;i++)
while (i<n&&a[i+].y-a[i+].x==a[i].y-a[i].x) from[a[i+].i][]=a[i].i,i++;
sort(a,a+n+,cmp3);
for (int i=;i<=n;i++)
while (i<n&&a[i+].x+a[i+].y==a[i].x+a[i].y) from[a[i+].i][]=a[i].i,i++;
sort(a,a+n+,cmp4);
for (int i=;i<=n;i++)
while (i<n&&a[i+].x==a[i].x) from[a[i+].i][]=a[i].i,i++;
sort(a,a+n+,cmp);
memset(f,,sizeof(f));
f[]=;
for (int i=;i<=n;i++)
{
int t=i;ans[i]=f[i]=max(max(f[from[i][]],f[from[i][]]),f[from[i][]])+;
while (t<n&&a[t+].y==a[i].y)
t++,ans[t]=f[t]=max(max(f[from[t][]],f[from[t][]]),f[from[t][]])+;
int mx=-N;
for (int j=i;j<=t;j++)
g[j]=max(f[j],mx+j-i),mx=max(mx,f[j]);
mx=-N;
for (int j=t;j>=i;j--)
h[j]=max(f[j],mx+t-j),mx=max(mx,f[j]);
for (int j=i;j<=t;j++)
f[j]=max(g[j],h[j]);
i=t;
}
int x=,y=;
for (int i=;i<=n;i++) if (f[i]>f[x]) tot=f[i],y=x=i;
for (int i=;i<=n;i++) if (f[i]==tot) tagend[i]=;
cout<<tot<<endl;
memset(p,,sizeof(p));
for (int i=n;i>=;i--)
{
int t=i;
while (t>&&a[t-].y==a[i].y) t--;
if (t<=x&&x<=i)
{
if (f[x]==ans[x]) pre[x]=x;
for (int j=t;j<x;j++)
if (ans[j]+x-t==f[x]) pre[x]=j;
for (int j=i;j>x;j--)
if (ans[j]+i-x==f[x]) pre[x]=j;
x=pre[x];
if (f[from[x][]]+==ans[x]) pre[x]=from[x][];
if (f[from[x][]]+==ans[x]) pre[x]=from[x][];
if (f[from[x][]]+==ans[x]) pre[x]=from[x][];
x=pre[x];
}
for (int j=t;j<=i;j++)
if (tagend[j]&&f[j]==ans[j]) tagstart[j]=;
for (int j=t;j<=i;j++)
{
if (ans[j]>=&&flag[ans[j]]) tagstart[j]=;
if (tagend[j]) flag[f[j]+j-i]=;
}
for (int j=t;j<=i;j++)
if (tagend[j]) flag[f[j]+j-i]=;
for (int j=i;j>=t;j--)
{
if (ans[j]>=&&flag[ans[j]]) tagstart[j]=;
if (tagend[j]) flag[f[j]+t-j]=;
}
for (int j=i;j>=t;j--)
if (tagend[j]) flag[f[j]+t-j]=;
for (int j=t;j<=i;j++)
if (tagstart[j])
{
if (f[from[j][]]+==ans[j]) tagend[from[j][]]=,addedge(from[j][],j,N-),degree[from[j][]]++,degree[j]--;
if (f[from[j][]]+==ans[j]) tagend[from[j][]]=,addedge(from[j][],j,N-),degree[from[j][]]++,degree[j]--;
if (f[from[j][]]+==ans[j]) tagend[from[j][]]=,addedge(from[j][],j,N-),degree[from[j][]]++,degree[j]--;
}
i=t;
}
print(y);
cout<<endl;
for (int i=;i<=n;i++)
if (degree[i]>) addedge(i,T,degree[i]);
else addedge(S,i,-degree[i]);
for (int i=;i<=n;i++) addedge(SS,i,N),addedge(i,ST,N);
addedge(ST,SS,N);
dinic(S,T);
tot=;
dinic(ST,SS);
cout<<N-tot;
return ;
}

BZOJ4200 NOI2015小园丁与老司机(动态规划+上下界网络流)的更多相关文章

  1. luogu P2304 [NOI2015]小园丁与老司机 dp 上下界网络流

    LINK:小园丁与老司机 苦心人 天不负 卧薪尝胆 三千越甲可吞吴 AC的刹那 真的是泪目啊 很久以前就写了 当时记得特别清楚 写到肚子疼.. 调到胳膊疼.. ex到根不不想看的程度. 当时wa了 一 ...

  2. [NOI2015]小园丁与老司机(DP+上下界最小流)

    由于每行点的个数不超过1000,所以行内DP可以使用$O(n^2)$算法. 先找到每个点所能直接到达的所有点(x,y,x+y或x-y相同),用排序实现. 第一问:以行为阶段,对于每行,暴力枚举最有路径 ...

  3. [BZOJ4200][Noi2015]小园丁与老司机

    4200: [Noi2015]小园丁与老司机 Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 106  Solved ...

  4. UOJ#132&bzoj4200[Noi2015]小园丁与老司机

    看,这是一个传送门 Part A 把坐标离散化,按照纵坐标为第一关键字,横坐标为第二关键字排序 以$f_i$记录来到$i$这个点最多经过点数,那么答案显而易见就是$f_i$加上该层点数 转移的话就是分 ...

  5. bzoj4200: [Noi2015]小园丁与老司机(可行流+dp)

    传送门 这该死的码农题…… 题解在这儿->这里 //minamoto #include<iostream> #include<cstdio> #include<cs ...

  6. [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机

    [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机 试题描述 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 \(n\) 棵许愿 ...

  7. 【BZOJ4200】[Noi2015]小园丁与老司机 DP+最小流

    [BZOJ2839][Noi2015]小园丁与老司机 Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2, ...

  8. uoj132/BZOJ4200/洛谷P2304 [Noi2015]小园丁与老司机 【dp + 带上下界网络流】

    题目链接 uoj132 题解 真是一道大码题,,,肝了一个上午 老司机的部分是一个\(dp\),观察点是按\(y\)分层的,而且按每层点的上限来看可以使用\(O(nd)\)的\(dp\),其中\(d\ ...

  9. BZOJ4200 & 洛谷2304 & UOJ132:[NOI2015]小园丁与老司机——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4200 https://www.luogu.org/problemnew/show/P2304 ht ...

随机推荐

  1. [Synthetic-data-with-text-and-image]

    0 引言 本文是之前为了解决如何将文字贴到图片上而编写的代码,默认是如发票一类的,所以并未考虑透视变换等.且采用的是pygame粘贴方式,之前也尝试过opencv的seamlessClone粘贴. 值 ...

  2. openssl生成签名与验证签名

    继上一篇RSA对传输信息进行加密解密,再写个生成签名和验证签名. 一般,安全考虑,比如接入支付平台时,请求方和接收方要互相验证是否是你,就用签名来看. 签名方式一般两种,对称加密和非对称加密.对称加密 ...

  3. C#中,使用显式类型转换(int)和Math.Round方法,将浮点数转换为整数的区别

    主要区别就是,显式类型转换(int)是将浮点数的整数部分截取出来,然后转换为整数,所以相当于是向下取整.而Math.Round方法是对浮点数进行四舍五入后,转换为整数. 新建一个.NET Core控制 ...

  4. Luogu4921/4931 情侣?给我烧了! 组合、递推

    4921 4931 第一眼看着就像容斥,但是容斥不怎么好做-- 第二眼想到错排,结果错排公式糊上去错了-- 不难考虑到可以先选\(K\)对情侣坐在一起,剩下\(N-K\)对错排 选\(K\)对情侣坐在 ...

  5. CF535E Tavas and Pashmaks 单调栈、凸包

    传送门 题意:有一场比赛,$N$个人参加.每个人有两种参数$a,b$,如果存在正实数$A,B$使得$\frac{A}{a_i} + \frac{B}{b_i}$在$i=x$处取得最大值(可以有多个最大 ...

  6. 小程序学习-iPhone X适配

    一.  安全区域(safe area) 与iPhone6/6s/7/8相比,iPhone X 无论是在屏幕尺寸.分辨率.甚至是形状上都发生了较大的改变,下面以iPhone 8作为参照物,先看看iPho ...

  7. flask seesion组件

    一.简介     flask中session组件可分为内置的session组件还有第三方flask-session组件,内置的session组件功能单一,而第三方的flask-sessoin可支持re ...

  8. 【php增删改查实例】第十九节 - session的使用: 让服务器知道你是谁?

    因为HTTP请求是一种无状态的请求,所谓无状态,就是服务器不会记录下你本次请求的信息.http它是基于请求 - 相应模式的一种数据传输协议.就是说,你发送一个请求,我服务器给你一个响应,这件事情就算完 ...

  9. Scala学习(七)---包和引入

    包和引入 摘要: 在本篇中,你将会了解到Scala中的包和引入语句是如何工作的.相比Java不论是包还是引入都更加符合常规,也更灵活一些.本篇的要点包括: 1. 包也可以像内部类那样嵌套 2. 包路径 ...

  10. Nginx Windows版的服务安装和管理工具

    以前研究过负载均衡,最近正在项目上实施(从来没做过小项目以上级别的东西,哈),nginx挺好,不过Windows有点为难,小流量和本地不追求性能,简单易用是目标. Nginx Windows上并没有提 ...