luogu P2304 [NOI2015]小园丁与老司机 dp 上下界网络流
LINK:小园丁与老司机
苦心人 天不负 卧薪尝胆 三千越甲可吞吴 AC的刹那 真的是泪目啊
很久以前就写了 当时记得特别清楚
写到肚子疼..
调到胳膊疼..
ex到根不不想看的程度.
当时wa了 一直不知道哪里错了 今天又调了一下午 调出来了.
思路是这样的:
先进行分层dp dp的时候我是反着dp的 因为无论是考虑后续的方案输出还是建图.
从那些终点到起点进行dp对后续的处理带来非常大的便利.
定义\(f_i\)表示由上一层转移过来的最大值.\(w_i\)表示由同层/上一层转移过来的最大值.
之所以要\(w\)数组主要是对后续建图带来很大的便利.
不同层的转移我直接map了 当然也可以离散。
同层的转移我是利用单调性优化的 所以总复杂度应该是\(nlogn\)
考虑输出方案 需要注意一些细节 但是不难.
建图是重点。刚才是反着dp 此时可以正着建图 有点topsort的意思.
然后不断维护当前层是从哪个点出来的和进来的从而把完整的图给建立出来.
最后是最小费用流 先建一个超超级源 和 超超级汇 然后 汇源连边 跑循环流 最后再把源汇边断掉 跑汇源的最大流即可.
code
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000
#define inf 1000000000
#define ld long double
#define mod 1004535809
#define pb push_back
#define put(x) printf("%d\n",x)
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define pii pair<int,int>
#define F first
#define S second
#define mk make_pair
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
const int MAXN=50100;
int n,r,flag,ql,qr,cnt,len=1,SS,TT,l;
int vis[MAXN],mark[MAXN],vis1[MAXN],cur[MAXN],d[MAXN];
int q[MAXN],f[MAXN],g[MAXN],w[MAXN],c[MAXN];
int lin[MAXN],ver[MAXN<<3],nex[MAXN<<3],e[MAXN<<3];
struct wy
{
	int x,y,id;
	int L,R;
	int friend operator <(wy a,wy b){return a.y==b.y?a.x<b.x:a.y>b.y;}
}t[MAXN];
struct jl{int s1,s2,s3;}s[MAXN];
map<int,pii>H1,H2,H3;
inline void get_path(int x,int v)
{
	if(x!=n)printf("%d ",t[x].id);
	if(w[x]==1||(v&&f[x]==1))return;
	int ww=v==1?g[x]:c[x];
	if(t[ww].y!=t[x].y){get_path(ww,0);return;}
	else
	{
		if(ww>x)
		{
			for(int j=x-1;j;--j)
				if(t[j].y==t[x].y)printf("%d ",t[j].id);
				else break;
			for(int j=x+1;j!=ww;++j)printf("%d ",t[j].id);
		}
		else
		{
			for(int j=x+1;j<=n;++j)
				if(t[j].y==t[x].y)printf("%d ",t[j].id);
				else break;
			for(int j=x-1;j!=ww;--j)printf("%d ",t[j].id);
		}
	}
	get_path(ww,1);
}
inline void add(int x,int y,int z)
{
	ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
	ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
	//if(x==3&&y==qr)cout<<x<<' '<<y<<endl;
}
//map<int,int>W[MAXN];
inline void add(int x,int y,int L,int R)
{
	//if(W[x].find(y)!=W[x].end())cout<<"ww"<<endl;
	d[x]-=L;d[y]+=L;
	add(x,y,R-L);
}
inline int bfs(int SS,int TT)
{
	for(int i=0;i<=cnt;++i)vis[i]=0,cur[i]=lin[i];
	l=r=0;q[++r]=SS;vis[SS]=1;
	while(++l<=r)
	{
		int x=q[l];
		for(int i=lin[x];i;i=nex[i])
		{
			int tn=ver[i];
			if(vis[tn]||!e[i])continue;
			vis[tn]=vis[x]+1;
			q[++r]=tn;
			if(tn==TT)return 1;
		}
	}
	return 0;
}
inline int dinic(int x,int TT,int flow)
{
	if(x==TT)return flow;
	int res=flow,k;
	for(int i=cur[x];i&&res;i=nex[i])
	{
		cur[x]=i;
		int tn=ver[i];
		if(vis[x]+1==vis[tn]&&e[i])
		{
			k=dinic(tn,TT,min(e[i],flow));
			if(!k){vis[tn]=0;continue;}
			res-=k;e[i]-=k;e[i^1]+=k;
		}
	}
	return flow-res;
}
int main()
{
	//freopen("1.in","r",stdin);
	cnt=n=read();
	for(int i=1;i<=n;++i)
	{
		int x,y;
		x=read();y=read();
		t[i]=(wy){x,y,i};
	}
	t[0]=(wy){0,0};
	sort(t,t+1+n);
	for(int i=0;i<=n;++i)
	{
		if(i&&t[i].y!=t[i-1].y)//鍚岃dp
		{
			int maxx=-r,p;//maxx琛ㄧず鏈€澶у€?p琛ㄧず鍐崇瓥浣嶇疆
			for(int j=1;j<=r;++j)
			{
				int tn=q[j];
				w[tn]=f[tn];c[tn]=g[tn];
				if(maxx+r>w[tn])
				{
					w[tn]=maxx+r;
					c[tn]=p;
				}
				if(f[tn]-j>maxx)maxx=f[tn]-j,p=tn;
				t[tn].L=f[tn]-j+r;
			}
			maxx=-r;
			for(int j=r;j>=1;--j)
			{
				int tn=q[j];
				if(maxx>w[tn])
				{
					w[tn]=maxx;
					c[tn]=p;
				}
				if(f[tn]+j-1>maxx)maxx=f[tn]+j-1,p=tn;
				t[tn].R=f[tn]+j-1;
				int x=t[tn].x,y=t[tn].y;
				H1[x+y]=mk(w[tn],tn);H2[x]=mk(w[tn],tn);H3[y-x]=mk(w[tn],tn);
			}
			r=0;
		}
		//if(i==n)cout<<"ww"<<endl;
		q[++r]=i;
		int x=t[i].x;int y=t[i].y;
		pii w1=H1[x+y];s[i].s1=w1.F==0?-1:w1.S;//宸︿笂
		if(w1.F+1>f[i])f[i]=w1.F+1,g[i]=w1.S;
		w1=H2[x];s[i].s2=w1.F==0?-1:w1.S;//涓婃柟
		if(w1.F+1>f[i])f[i]=w1.F+1,g[i]=w1.S;
		w1=H3[y-x];s[i].s3=w1.F==0?-1:w1.S;//鍙充笂
		if(w1.F+1>f[i])f[i]=w1.F+1,g[i]=w1.S;
	}
	printf("%d\n",f[n]-1);w[n]=f[n];
	//rep(1,n,i)put(f[i]);
	get_path(n,1);puts("");
	ql=++cnt;qr=++cnt;
	add(ql,n,INF);
	vis[n]=1;r=0;
	for(int i=n;i>=0;--i)
	{
		q[++r]=i;
		if(i==0||t[i].y!=t[i-1].y)
		{
			for(int j=1;j<=r;++j)
			{
				int tn=q[j];
				if(mark[t[tn].L])vis1[tn]=1;
				if(vis[tn])
				{
					mark[w[tn]]=1;
					add(tn,qr,INF);
				}
			}
			for(int j=1;j<=r;++j)mark[w[q[j]]]=0;
			for(int j=r;j>=1;--j)
			{
				int tn=q[j];
				if(mark[t[tn].R])vis1[tn]=1;
				if(vis[tn])mark[w[tn]]=1;
			}
			for(int j=1;j<=r;++j)
			{
				int tn=q[j];
				mark[w[tn]]=0;
				if(vis[tn]&&f[tn]==w[tn])vis1[tn]=1;
				if(vis1[tn])add(ql,tn,INF);
				if(!vis1[tn])continue;
				int s1=s[tn].s1;
				int s2=s[tn].s2;
				int s3=s[tn].s3;
				if(s1==-1&&s2==-1&&s3==-1){add(tn,qr,INF);continue;}
				if(s1!=-1&&w[s1]==f[tn]-1){vis[s1]=1;add(tn,s1,1,INF);}
				if(s2!=-1&&w[s2]==f[tn]-1){vis[s2]=1;add(tn,s2,1,INF);}
				if(s3!=-1&&w[s3]==f[tn]-1){vis[s3]=1;add(tn,s3,1,INF);}
			}
			r=0;
		}
	}
	SS=++cnt;TT=++cnt;
	int flow,sum=0;
	for(int i=0;i<=cnt-2;++i)
	{
		if(d[i]>0)add(SS,i,d[i]);
		if(d[i]<0)add(i,TT,-d[i]);
	}
	//cout<<ans<<endl;
	add(qr,ql,INF);
	while(bfs(SS,TT))
		while((flow=dinic(SS,TT,inf)))sum-=flow;
	sum=e[len];e[len^1]=0;
	while(bfs(qr,ql))while((flow=dinic(qr,ql,inf)))sum-=flow;
	printf("%d\n",sum);
	return 0;
}
luogu P2304 [NOI2015]小园丁与老司机 dp 上下界网络流的更多相关文章
- [NOI2015]小园丁与老司机(DP+上下界最小流)
		
由于每行点的个数不超过1000,所以行内DP可以使用$O(n^2)$算法. 先找到每个点所能直接到达的所有点(x,y,x+y或x-y相同),用排序实现. 第一问:以行为阶段,对于每行,暴力枚举最有路径 ...
 - 【BZOJ4200】[Noi2015]小园丁与老司机 DP+最小流
		
[BZOJ2839][Noi2015]小园丁与老司机 Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2, ...
 - uoj132/BZOJ4200/洛谷P2304   [Noi2015]小园丁与老司机  【dp + 带上下界网络流】
		
题目链接 uoj132 题解 真是一道大码题,,,肝了一个上午 老司机的部分是一个\(dp\),观察点是按\(y\)分层的,而且按每层点的上限来看可以使用\(O(nd)\)的\(dp\),其中\(d\ ...
 - 【洛谷2304_LOJ2134】[NOI2015]小园丁与老司机(动态规划_网络流)
		
题目: 洛谷 2304 LOJ 2134 (LOJ 上每个测试点有部分分) 写了快一天 -- 好菜啊 分析: 毒瘤二合一题 -- 注意本题(及本文)使用 \(x\) 向右,\(y\) 向上的「数学坐标 ...
 - 并不对劲的loj2134:uoj132:p2304:[NOI2015]小园丁与老司机
		
题目大意 给出平面直角坐标系中\(n\)(\(n\leq5*10^4\))个点,第\(i\)个点的坐标是\(x_i,y_i(|x_i|\leq10^9,1\leq y_i\leq10^9)\),只有朝 ...
 - [BZOJ4200][Noi2015]小园丁与老司机
		
4200: [Noi2015]小园丁与老司机 Time Limit: 20 Sec Memory Limit: 512 MBSec Special JudgeSubmit: 106 Solved ...
 - 【BZOJ4200】【NOI2015】小园丁与老司机(动态规划,网络流)
		
[BZOJ4200][NOI2015]小园丁与老司机(动态规划,网络流) 题面 BZOJ权限题,洛谷链接 题解 一道二合一的题目 考虑第一问. 先考虑如何计算六个方向上的第一个点. 左右上很好考虑,只 ...
 - [UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机
		
[UOJ#132][BZOJ4200][luogu_P2304][NOI2015]小园丁与老司机 试题描述 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 \(n\) 棵许愿 ...
 - BZOJ4200 & 洛谷2304 & UOJ132:[NOI2015]小园丁与老司机——题解
		
https://www.lydsy.com/JudgeOnline/problem.php?id=4200 https://www.luogu.org/problemnew/show/P2304 ht ...
 
随机推荐
- Spring Security 实战干货:图解Spring Security中的Servlet过滤器体系
			
1. 前言 我在Spring Security 实战干货:内置 Filter 全解析对Spring Security的内置过滤器进行了罗列,但是Spring Security真正的过滤器体系才是我们了 ...
 - 「疫期集训day5」火焰
			
我们就像一把穿刺敌人的利刃,把敌人开肠破肚----凡尔登高地前气势汹汹的德军 今天没有考试,挺好,有时间自己做题了 今天主要复习+学习了数据结构,列了个表: 已完成:单调队列,线段树,set/vect ...
 - Github和Azure DevOps的代码同步
			
[前言]Github和Azure DevOps都提供了Git代码库功能,那么有没有办法将两边的代码库进行同步呢,答案是肯定的.这里的操作我都是用Azure DevOps的Pipelines功能来完成的 ...
 - day78 通过axios实现数据请求
			
目录 一.axios提供http请求的两个常用方法 二.json 1.json数据的语法 2 js中提供json数据转化的方式 三 ajax 1 数据接口 2 ajax在jq和vue的不同使用 3 同 ...
 - Maven 专题(五):Maven核心概念详解(一)
			
**Maven 的核心程序中仅仅定义了抽象的生命周期,而具体的操作则是由 Maven 的插件来完成的.**可是 Maven 的插件并不包含在 Maven 的核心程序中,在首次使用时需要联网下载. 下载 ...
 - Mysql 实例:mysql语句练习50题(sqlalchmy写法)
			
为了练习sql语句,在网上找了一些题,自己做了一遍,收益颇多.很多地方换一种思路,有更好的写法,欢迎指正. 题目地址:https://blog.csdn.net/fashion2014/article ...
 - C#-CLR note - 26线程
			
开篇 async/wait的使用 static async Task Main(string[] args) { Console.WriteLine("start-- "); va ...
 - 【RPA Starter第三课】第一个Uipath项目:HelloWord
			
最后是一个小项目,开启使用Uipath.Uipath云平台,Uipath Orchestrator,Uipath Studio,发布项目.怎么启动机器人.都有详细的步骤. Uipath 的账号是通用的 ...
 - [Qt2D绘图]-06QPainter的复合模式&&双缓冲绘图&&绘图中的其他问题
			
本篇读书笔记主要记录QPainter的复合模式&&双缓冲绘图&&绘图中的其他问题 大纲: 复合模式 双缓冲绘图 绘图中的其他问题 ...
 - vuex : 用vuex控制侧栏点亮状态
			
上代码. xxx.vue <template> <div id="xxx"> <div class="layout"> &l ...