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

时间:2022-09-11 20:21:08

4200: [Noi2015]小园丁与老司机

Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special Judge
Submit: 106  Solved: 58
[Submit][Status][Discuss]

Description

小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面。田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2,3,…,n,每棵树可以看作平面上的一个点,其中第 ii 棵树 (1≤i≤n1≤i≤n) 位于坐标 (xi,yi)(xi,yi)。任意两棵树的坐标均不相同。
老司机 Mr. P 从原点 (0,0)(0,0) 驾车出发,进行若干轮行动。每一轮,Mr. P 首先选择任意一个满足以下条件的方向:
为左、右、上、左上 45∘45∘ 、右上 45∘45∘ 五个方向之一。
沿此方向前进可以到达一棵他尚未许愿过的树。
完成选择后,Mr. P 沿该方向直线前进,必须到达该方向上距离最近的尚未许愿的树,在树下许愿并继续下一轮行动。如果没有满足条件的方向可供选择,则停止行动。他会采取最优策略,在尽可能多的树下许愿。若最优策略不唯一,可以选择任意一种。
不幸的是,小园丁 Mr. S 发现由于田野土质松软,老司机 Mr. P 的小汽车在每轮行进过程中,都会在田野上留下一条车辙印,一条车辙印可看作以两棵树(或原点和一棵树)为端点的一条线段。
在 Mr. P 之后,还有很多许愿者计划驾车来田野许愿,这些许愿者都会像 Mr. P 一样任选一种最优策略行动。Mr. S 认为非左右方向(即上、左上 45∘45∘ 、右上 45∘45∘ 三个方向)的车辙印很不美观,为了维护田野的形象,他打算租用一些轧路机,在这群许愿者到来之前夯实所有“可能留下非左右方向车辙印”的地面。
“可能留下非左右方向车辙印”的地面应当是田野上的若干条线段,其中每条线段都包含在某一种最优策略的行进路线中。每台轧路机都采取满足以下三个条件的工作模式:
从原点或任意一棵树出发。
只能向上、左上 45∘45∘ 、右上 45∘45∘ 三个方向之一移动,并且只能在树下改变方向或停止。
只能经过“可能留下非左右方向车辙印”的地面,但是同一块地面可以被多台轧路机经过。
现在 Mr. P 和 Mr. S 分别向你提出了一个问题:
请给 Mr .P 指出任意一条最优路线。
请告诉 Mr. S 最少需要租用多少台轧路机。
 

Input

输入文件的第 1 行包含 1 个正整数 n,表示许愿树的数量。

接下来 n 行,第 i+1 行包含 2个整数 xi,yi,中间用单个空格隔开,表示第 i 棵许愿树的坐标。
 

Output

输出文件包括 3 行。
输出文件的第 1 行输出 1 个整数 m,表示 Mr. P 最多能在多少棵树下许愿。
输出文件的第 2 行输出 m 个整数,相邻整数之间用单个空格隔开,表示 Mr. P 应该依次在哪些树下许愿。
输出文件的第 3 行输出 1 个整数,表示 Mr. S 最少需要租用多少台轧路机。
 

Sample Input

6
-1 1
1 1
-2 2
0 8
0 9
0 10

Sample Output

3
2 1 3
3

explanation

最优路线 2 条可许愿 3 次:(0,0)→(1,1)→(−1,1)→(−2,2)(0,0)→(1,1)→(−1,1)→(−2,2) 或 (0,0)→(0,8)→(0,9)→(0,10)(0,0)→(0,8)→(0,9)→(0,10)。 至少 3 台轧路机,路线是 (0,0)→(1,1)(0,0)→(1,1),(−1,1)→(−2,2)(−1,1)→(−2,2) 和 (0,0)→(0,8)→(0,9)→(0,10)(0,0)→(0,8)→(0,9)→(0,10)。

HINT

Source

 

[Submit][Status][Discuss]

HOME Back

第一问按Y排序,map记录每个向上、左、右方向最近的点,对于y坐标相同的点按x排序,如果$x_i>x_j$,一定是从j走到最左在走回i,如果$x_i<x_j$,一定是从j走到最走在走回i。维护一个单调栈即可。

第二问只需要在DP的同时记录决策点,输出路径。

第三问相当于判断每条边是否可以存在于最长路中,然后下界为1跑最小流。如果判断每条边可以倒着DP一遍考虑是否两端和等于ans。注意,倒着DP和正着DP会有差别。

 #include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50050
#define S (n+1)
#define T (n+2)
#define SS (n+3)
#define TT (n+4)
using namespace std;
struct dp{int x,y,id,f,from;bool f1,f2;}a[N],b[N];
int n,f[N],g[N],X[N],Y[N];
int head[N],tot,d[N];
struct edge{int next,to,v;}e[];
inline void add(int u,int v,int w)
{
e[tot]=(edge){head[u],v,w};
head[u]=tot++;
e[tot]=(edge){head[v],u,};
head[v]=tot++;
}
int SAP(int start,int end,int n)
{
int u,neck,tmp,i,flow_ans=,cur_flow;
int numh[N],d[N],cure[N],pre[N];
memset(d,,sizeof(d));
memset(numh,,sizeof(numh));
memset(pre,-,sizeof(pre));
for(int i=;i<=n;i++)
cure[i]=head[i];
numh[]=n;
u=start;
while(d[start]<n)
{
if(u==end)
{
cur_flow=1e9;
for(i=start;i!=end;i=e[cure[i]].to)
if(cur_flow>e[cure[i]].v)
neck=i,cur_flow=e[cure[i]].v;
for(i=start;i!=end;i=e[cure[i]].to)
{
tmp=cure[i];
e[tmp].v-=cur_flow;
e[tmp^].v+=cur_flow;
}
flow_ans+=cur_flow;
u=neck;
}
for(i=cure[u];i!=-;i=e[i].next)
if(e[i].v&&d[u]==d[e[i].to]+)break;
if(i!=-)
{
cure[u]=i;
pre[e[i].to]=u;
u=e[i].to;
}
else
{
if(--numh[d[u]]==)break;
cure[u]=head[u];
for(tmp=n,i=head[u];i!=-;i=e[i].next)
if(e[i].v)tmp=min(tmp,d[e[i].to]);
d[u]=tmp+;
numh[d[u]]++;
if(u!=start)u=pre[u];
}
}
return flow_ans;
}
bool operator<(dp x,dp y)
{
if(x.y!=y.y)return x.y<y.y;
return x.x<y.x;
}
inline void update(int i,int j)
{
if(a[i].f<a[j].f+)
a[i].f=a[j].f+,a[i].from=j,a[i].f1=;
}
void print(int x,bool f)
{
if(x==n+)return;
if(!f)print(a[x].from,a[x].f1);
else print(b[x].from,);
if(!a[x].f1||f)
printf("%d ",a[x].id);
else if(!a[x].f2)
{
for(int i=a[x].from-;a[i].y==a[x].y;i--)
printf("%d ",a[i].id);
for(int i=a[x].from+;i<=x;i++)
printf("%d ",a[i].id);
}
else
{
for(int i=a[x].from+;a[i].y==a[x].y;i++)
printf("%d ",a[i].id);
for(int i=a[x].from-;i>=x;i--)
printf("%d ",a[i].id);
}
}
map<int,int>L,R,U;
void solve(int ans)
{
memset(head,-,sizeof(head));
L.clear();
R.clear();
U.clear();
for(int i=;i<=n;i++)
X[i]=a[n+-i].x,Y[i]=a[n+-i].y;
X[n+]=Y[n+]=;
for(int i=;i<=n;i++)f[i]=;
for(int l=,r,x;l<=n+;l=r+)
{
for(r=l;r<=n&&Y[r+]==Y[r];r++);
for(int i=l;i<=r;i++)
{
x=U[X[i]];
if(x)
{
f[i]=max(f[i],f[x]+);
if((a[n+-i].f||i==n+)&&a[n+-i].f+f[x]==ans)
{
add(n+-x,n+-i,1e9);
d[n+-x]--;d[n+-i]++;
}
}
x=L[X[i]+Y[i]];
if(x)
{
f[i]=max(f[i],f[x]+);
if((a[n+-i].f||i==n+)&&a[n+-i].f+f[x]==ans)
{
add(n+-x,n+-i,1e9);
d[n+-x]--;d[n+-i]++;
}
}
x=R[X[i]-Y[i]];
if(x)
{
f[i]=max(f[i],f[x]+);
if((a[n+-i].f||i==n+)&&a[n+-i].f+f[x]==ans)
{
add(n+-x,n+-i,1e9);
d[n+-x]--;d[n+-i]++;
}
}
U[X[i]]=i;
L[X[i]+Y[i]]=i;
R[X[i]-Y[i]]=i;
}
for(int i=l;i<=r;i++)g[i]=f[i];
int maxid=;
for(int i=l+;i<=r;i++)
{
if(!maxid||g[i-]+(r-i+)>g[maxid]+(r-maxid))maxid=i-;
if(f[i]<g[maxid]+(r-maxid))
f[i]=g[maxid]+(r-maxid);
}
maxid=;
for(int i=r-;i>=l;i--)
{
if(!maxid||g[i+]+(i+-l)>g[maxid]+(maxid-l))maxid=i+;
if(f[i]<g[maxid]+(maxid-l))
f[i]=g[maxid]+(maxid-l);
}
}
for(int i=;i<=n;i++)
add(S,i,1e9),add(i,T,1e9);
for(int i=;i<=n;i++)
if(d[i]>)add(SS,i,d[i]);
else add(i,TT,-d[i]);
SAP(SS,TT,TT+);
add(T,S,1e9);
SAP(SS,TT,TT+);
printf("%d\n",e[tot-].v);
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].y),a[i].id=i;
sort(a+,a+n+);
U[]=L[]=R[]=n+;
for(int l=,r,x;l<=n;l=r+)
{
for(r=l;r<n&&a[r+].y==a[r].y;r++);
for(int i=l;i<=r;i++)
{
x=U[a[i].x];
if(x)update(i,x);
x=L[a[i].x+a[i].y];
if(x)update(i,x);
x=R[a[i].x-a[i].y];
if(x)update(i,x);
}
for(int i=l;i<=r;i++)b[i]=a[i];
int maxid=;
for(int i=l+;i<=r;i++)
{
if(b[i-].f>b[maxid].f)maxid=i-;
if(maxid&&a[i].f<b[maxid].f+(i-l))
{
a[i].f=b[maxid].f+(i-l);
a[i].f1=;a[i].f2=;a[i].from=maxid;
}
}
maxid=;
for(int i=r-;i>=l;i--)
{
if(b[i+].f>b[maxid].f)maxid=i+;
if(maxid&&a[i].f<b[maxid].f+(r-i))
{
a[i].f=b[maxid].f+(r-i);
a[i].f1=;a[i].f2=;a[i].from=maxid;
}
}
for(int i=l;i<=r;i++)
if(a[i].f)
{
U[a[i].x]=i;
L[a[i].x+a[i].y]=i;
R[a[i].x-a[i].y]=i;
}
}
int ans=,id=n+;
for(int i=;i<=n;i++)
if(a[i].f>ans)
ans=a[i].f,id=i;
printf("%d\n",ans);
print(id,);puts("");
solve(ans);
}

[BZOJ4200][Noi2015]小园丁与老司机的更多相关文章

  1. BZOJ4200 NOI2015小园丁与老司机(动态规划&plus;上下界网络流)

    一看上去就是一个二合一的题.那么先解决第一部分求最优路线(及所有可能在最优路线上的线段). 由于不能往下走,可以以y坐标作为阶段.对于y坐标不同的点,我们将可以直接到达的两点连边,显然这样的边的个数是 ...

  2. UOJ&num;132&amp&semi;bzoj4200&lbrack;Noi2015&rsqb;小园丁与老司机

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

  3. bzoj4200&colon; &lbrack;Noi2015&rsqb;小园丁与老司机(可行流&plus;dp)

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

  4. &lbrack;UOJ&num;132&rsqb;&lbrack;BZOJ4200&rsqb;&lbrack;luogu&lowbar;P2304&rsqb;&lbrack;NOI2015&rsqb;小园丁与老司机

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

  5. 【BZOJ4200】&lbrack;Noi2015&rsqb;小园丁与老司机 DP&plus;最小流

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

  6. luogu P2304 &lbrack;NOI2015&rsqb;小园丁与老司机 dp 上下界网络流

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

  7. uoj132&sol;BZOJ4200&sol;洛谷P2304 &lbrack;Noi2015&rsqb;小园丁与老司机 【dp &plus; 带上下界网络流】

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

  8. BZOJ4200 &amp&semi; 洛谷2304 &amp&semi; UOJ132:&lbrack;NOI2015&rsqb;小园丁与老司机——题解

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

  9. 【bzoj4200】&lbrack;Noi2015&rsqb;小园丁与老司机 STL-map&plus;dp&plus;有上下界最小流

    题目描述 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2,3,…,n,每棵树可以看作平面上的一个点,其中第 ii 棵树 (1≤ ...

随机推荐

  1. Python中文乱码

    1,注意:请使用智慧型浏览器 "CHROME" 配合理解和运作本文中提到的程序. 2,提示:谷歌的CHROME浏览器是迄今为止最智慧的浏览器,没有之一,只有第一. 3,谷歌的CHR ...

  2. ASP&period;NET MVC 4 WebAPI Simple Sample

    // Controllers.cs namespace Microshaoft.WebApi.Controllers { using Microshaoft.WebApi.Models; using ...

  3. Java中的堆和栈的区别

    当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先 ...

  4. 浅谈sql 、linq、lambda 查询语句的区别

    浅谈sql .linq.lambda 查询语句的区别 LINQ的书写格式如下: from 临时变量 in 集合对象或数据库对象 where 条件表达式 [order by条件] select 临时变量 ...

  5. 进程间通信&lpar;IPC&rpar; 简介

    IPC是进程间通信的简称.传统上该术语描述的是运行在某个操作系统之上的不同进程间消息传递的不同方式. 我们讨论分为四个领域: 消息传递(管道,FIFO,消息队列(system v消息队列,posix消 ...

  6. ios中block中的探究

    http://blog.csdn.net/jasonblog/article/details/7756763

  7. 《小C QQ空间转帖、分享工具》之QQ空间数据传递的g&lowbar;tk算法&lpar;C&num;&rpar;

    原文地址:http://user.qzone.qq.com/419067339/2 public string GET_HTTP(string url, string referer_post, st ...

  8. FFmpeg编译iOS静态库

    第一步:下载gas-preprocessor 1.1 下载https://github.com/libav/gas-preprocessor 1.2 拷贝 gas-preprocessor.pl 到 ...

  9. 【Python 14】分形树绘制2&period;0(重复五角星&plus;Turtle库文档)

    1.案例描述 加入循环操作绘制重复不同大小的图形 2.案例分析 3.turtle库补充 # 画笔控制函数 turtle.penup() # 抬起画笔,之后移动画笔不绘制图形 turtle.pendow ...

  10. 自学华为IoT物联网&lowbar;09 OceanConnect业务流程

    点击返回自学华为IoT物流网 自学华为IoT物联网_09 OceanConnect业务流程 1.  物流网重要的连个协议介绍 1.1  重要物联网协议介绍----MQTT MQTT(消息队列遥测传输) ...