题目大意

给出平面直角坐标系中\(n\)(\(n\leq5*10^4\))个点,第\(i\)个点的坐标是\(x_i,y_i(|x_i|\leq10^9,1\leq y_i\leq10^9)\),只有朝正上方、正左方、正右方、右上方45°、左上方45°走的路,只能在给出的点处拐弯

解决两个问题:

1.从点\((0,0)\)出发,只能在没走到过的点处拐弯,求最多能走多少个给出的点并输出方案

2.从点\((0,0)\)或者任意一个给出的点出发,不能朝正左方、正右方走,而且只能走被一种第1问的最优方案包含的路,求至少要走几次才能覆盖所有被一种第1问的最优路线包含了的路

题解

先预处理每个点朝正上方、正左方、正右方、右上方45°、左上方45°走遇到的第一个点

1.

把\(y_i\)相同的点归为同一层

设\(f(i)\)表示如果从点\(i\)进入\(i\)所在的那一层,那么在\(i\)所在的层和上面的层最多能走多少给出的点

发现如果从\(i\)进入某一层,从\(j\)离开这一层,那么当\(i<j\)时该层最多走\(j\)左边所有点,当\(i>j\)时该层最多走\(j\)右边所有点,\(i=j\)时只会走到一个点

这是因为当\(i<j\)时,可以先向左走,走到\(i\)左边所有点,再向右走,走\(i,j\)之间的所有点(答案不少于\(j\)左边所有点)

而如果走到了\(j\)右边的点,就一定会走过\(j\),无法再从\(j\)离开这一层了(答案不多于\(j\)左边所有点)

\(i>j\)时同理

设\(h(x)\)表示点\(x\)左上方45°的第一个点、右上方45°的第一个点、正上方的第一个点的\(f\)的最大值

那就有\(f(i)=max(max\{h(j)+(j左边的点数)\mid i<j\},max\{h(j)+(j右边的点数)\mid i>j\},max\{h(j)+1\mid i=j\})\)

\(f(0)\)就是第一问的答案

递推\(f\)时要记方案

2.

设\(g(i)\)表示如果从点\(i\)离开\(i\)所在的那一层,那么离开时在\(i\)所在的层和下面的层最多能走多少给出的点

会发现对于一个点\(i\),它 左上方45°的第一个点 或 右上方45°的第一个点 或 正上方的第一个点 \(j\)如果满足\(g(i)+f(j)=f(0)\)那么\(i->j\)就是一条出现在第一问最优方案中的路

发现这个可以是个有上下界最小流,每条路看成下界为1,上界为\(\infty\)的边

也就是连上界为\(\infty\)的边,算出每个点的出入度后,出>入的连\(该点->超汇\)且上界为\(出-入\)的边,出<入的连\(超源->该点\)且上界为\(入-出\)的边

通过观察题意发现这题一定有解,满流就是超源到所有点的上界之和(也是所有点到超汇的上界之和),那就可以直接用(满流时的流量-重新建图后的流量)

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define maxn 50010
#define maxm (maxn*8)
#define LL long long
#define pre(x) (!maxto[ord[x]]?tl-x+1:f[maxto[ord[x]]]+tl-x+1)
#define suf(x) (!maxto[ord[x]]?x-hd+1:f[maxto[ord[x]]]+x-hd+1)
#define now(x) (!maxto[ord[x]]?1:f[maxto[ord[x]]]+1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
return;
}
int n,xi[maxn],yi[maxn],ord[maxn],up[maxn][3],f[maxn],g[maxn],t[maxn],maxto[maxn],out[maxn],rnk[maxn],maxflow,full;
int fir[maxn],nxt[maxm],dis[maxn],v[maxm],fl[maxm],cnt,in[maxn],S,T,inf=2147483647;
bool cmpl(int x,int y){return (xi[x]+yi[x]==xi[y]+yi[y])?(yi[x]<yi[y]):(xi[x]+yi[x]<xi[y]+yi[y]);}
bool cmpr(int x,int y){return (xi[x]-yi[x]==xi[y]-yi[y])?(yi[x]<yi[y]):(xi[x]-yi[x]<xi[y]-yi[y]);}
bool cmpx(int x,int y){return (xi[x]==xi[y])?(yi[x]<yi[y]):(xi[x]<xi[y]);}
bool cmpy(int x,int y){return (yi[x]==yi[y])?(xi[x]<xi[y]):(yi[x]>yi[y]);}
void ade(int u1,int v1,int fl1)
{
v[cnt]=v1,nxt[cnt]=fir[u1],fl[cnt]=fl1,fir[u1]=cnt++;
v[cnt]=u1,nxt[cnt]=fir[v1],fl[cnt]=0,fir[v1]=cnt++;
}
int hd,tl,q[maxn];
int bfs()
{
hd=1,tl=0;
rep(i,0,T)dis[i]=inf;
dis[T]=0,q[++tl]=T;
while(hd<=tl)
{
int u=q[hd++];
view(u,k)if(fl[k^1]&&dis[v[k]]==inf)dis[v[k]]=dis[u]+1,q[++tl]=v[k];
}
return dis[S]==inf?0:1;
}
int getf(int u,int nowflow)
{
if(u==T||nowflow==0)return nowflow;
int tmp,sum=0;
view(u,k)
{
if(!nowflow)break;
if(dis[v[k]]==dis[u]-1&&fl[k]&&(tmp=getf(v[k],min(nowflow,fl[k]))))fl[k]-=tmp,fl[k^1]+=tmp,nowflow-=tmp,sum+=tmp;
}
return sum;
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read();
rep(i,1,n)xi[i]=read(),yi[i]=read(),ord[i]=i;
sort(ord,ord+n+1,cmpl);
rep(i,0,n-1){if(xi[ord[i+1]]+yi[ord[i+1]]==xi[ord[i]]+yi[ord[i]])up[ord[i]][0]=ord[i+1];}
sort(ord,ord+n+1,cmpr);
rep(i,0,n-1){if(xi[ord[i+1]]-yi[ord[i+1]]==xi[ord[i]]-yi[ord[i]])up[ord[i]][1]=ord[i+1];}
sort(ord,ord+n+1,cmpx);
rep(i,0,n-1){if(xi[ord[i+1]]==xi[ord[i]])up[ord[i]][2]=ord[i+1];}
sort(ord,ord+n+1,cmpy);int pos;
rep(i,0,n)
{
hd=i,tl=i;
while(tl+1<=n&&yi[ord[tl+1]]==yi[ord[hd]])tl++;
rep(j,hd,tl)rep(k,0,2){if(up[ord[j]][k]&&(!maxto[ord[j]]||f[up[ord[j]][k]]>f[maxto[ord[j]]]))maxto[ord[j]]=up[ord[j]][k];}
pos=-1;
rep(j,hd,tl)f[ord[j]]=now(j),out[ord[j]]=(!maxto[ord[j]])?-1:ord[j],rnk[ord[j]]=j;
rep(j,hd,tl)
{
if(pos!=-1&&pre(pos)>f[ord[j]])f[ord[j]]=pre(pos),out[ord[j]]=ord[pos];
if(pos==-1||pre(j)>pre(pos))pos=j;
}pos=-1;
dwn(j,tl,hd)
{
if(pos!=-1&&suf(pos)>f[ord[j]])f[ord[j]]=suf(pos),out[ord[j]]=ord[pos];
if(pos==-1||suf(j)>suf(pos))pos=j;
}
i=tl;
}
//rep(i,0,n)cout<<"maxto:"<<maxto[i]<<" out:"<<out[i]<<endl;
write(f[0]-1),putchar('\n');
pos=maxto[0];
if(maxto[0])
{
do
{
if(rnk[out[pos]]<rnk[pos])
{
for(int i=rnk[pos];yi[ord[i]]==yi[pos];i++)write(ord[i]),putchar(' ');
for(int i=rnk[pos]-1;yi[ord[i]]==yi[pos]&&i>=rnk[out[pos]];i--)write(ord[i]),putchar(' ');
}
else if(rnk[out[pos]]>rnk[pos])
{
for(int i=rnk[pos];yi[ord[i]]==yi[pos];i--)write(ord[i]),putchar(' ');
for(int i=rnk[pos]+1;yi[ord[i]]==yi[pos]&&i<=rnk[out[pos]];i++)write(ord[i]),putchar(' ');
}
else write(pos),putchar(' ');
pos=out[pos];
if(out[pos]==-1)break;
pos=maxto[pos];
}while(pos);
putchar('\n');
}
rep(i,0,n)t[i]=g[i]=-n*4;g[0]=1;
dwn(i,n,0)
{
hd=i,tl=i;
while(hd-1>=0&&yi[ord[hd-1]]==yi[ord[tl]])hd--;
pos=-1;
rep(j,hd,tl)if(t[ord[j]]>0)g[ord[j]]=t[ord[j]]+1;
rep(j,hd,tl)
{
if(pos!=-1)g[ord[j]]=max(g[ord[j]],t[ord[pos]]+j-hd+1);
if(t[ord[j]]>0&&(pos==-1||t[ord[pos]]<t[ord[j]]))pos=j;
}pos=-1;
dwn(j,tl,hd)
{
if(pos!=-1)g[ord[j]]=max(g[ord[j]],t[ord[pos]]+tl-j+1);
if(t[ord[j]]>0&&(pos==-1||t[ord[pos]]<t[ord[j]]))pos=j;
}
rep(j,hd,tl)if(g[ord[j]]>0){rep(k,0,2)if(up[ord[j]][k])t[up[ord[j]][k]]=max(t[up[ord[j]][k]],g[ord[j]]);}
i=hd;
}
S=n+1,T=n+2;
rep(i,0,n)rep(k,0,2)if(up[i][k]&&g[i]>0&&g[i]+f[up[i][k]]==f[0])in[i]--,in[up[i][k]]++,ade(i,up[i][k],inf);
rep(i,0,n)
{
if(in[i]<0)ade(i,T,-in[i]);
if(in[i]>0)ade(S,i,in[i]),full+=in[i];
}
while(bfs())maxflow+=getf(S,inf);write(full-maxflow);
return 0;
}
/*
6
-1 1
1 1
-2 2
0 8
0 9
0 10
*/
/*
4
0 1
-2 1
2 1
3 2
*/

并不对劲的loj2134:uoj132:p2304:[NOI2015]小园丁与老司机的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

    Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special Judge Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维 ...

  8. [Noi2015]小园丁和老司机

    来自FallDream的博客,未经允许,请勿转载,谢谢. 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有n棵许愿树,编号1,2,3,…,n,每棵树可以看作平面上的一个点,其中 ...

  9. 【bzoj4200】[Noi2015]小园丁与老司机 STL-map+dp+有上下界最小流

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

随机推荐

  1. hdu 4710

    #include<stdio.h> #include<math.h> __int64 min(__int64 a,__int64 b) { return a<b?a:b; ...

  2. UOJ 58 (树上带修改的莫队)

    UOJ 58 糖果公园 Problem : 给一棵n个点的树,每个点上有一种颜色,对于一条路径上的点,若 i 颜色第 j 次出现对该路径权值的贡献为 w[i] * c[j], 每次询问一条路径的权值, ...

  3. java 并发基础,及案例分析

    对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了,然而并发问题是令我们大多数程序员头疼的问题,但话又说回来了,既然逃避不掉,那我们就坦然面对吧~今天就让我们深入研 ...

  4. Eclipse-Java代码规范和质量检查插件-Checkstyle

    CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具.它能够自动化代码规范检查过程,从而使得开发人员从这项重要但枯燥的任务中解脱出来.它可以根 ...

  5. 【转】c++ 如何批量初始化数组 fill和fill_n函数的应用

    http://blog.csdn.net/sunquana/article/details/9153213 一. fill和fill_n函数的应用: fill函数的作用是:将一个区间的元素都赋予val ...

  6. [外文理解] DDD创始人Eric Vans:要实现DDD原始意图,必须CQRS+Event Sourcing架构。

    原文:http://www.infoq.com/interviews/Technology-Influences-DDD# 要实现DDD(domain drive  design 领域驱动设计)原始意 ...

  7. Unity UGUI——概述、长处

    Unity4.6推出的新UI系统 长处:灵活.高速.可视化.效率高效果好.易于使用和扩展

  8. BZOJ 1122 POI2008 账本BBB 单调队列

    题目大意:给定一个由+1和−1构成的长度为n的序列,提供两种操作: 1.将某一位取反,花销为x 2.将最后一位移动到前一位.花销为y 要求终于p+sumn=q.且p+sumi≥0(1≤i≤n),求最小 ...

  9. Tcl学习之--列表|字典

    [列表|字典] Tcl使用列表来处理各种集合,比方一个目录中的全部文件,以及一个组件的全部选项.最简单的列表就是包括由随意个空格.制表符.换行符.分隔的随意多个元素的字符串.比方: JerryAlic ...

  10. leetcode:283. Move Zeroes(Java)解答

    转载请注明出处:z_zhaojun的博客 原文地址:http://blog.csdn.net/u012975705/article/details/50493772 题目地址:https://leet ...