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 ...
随机推荐
- 微信h5页面下拉露出网页来源的解决办法
微信h5页面下拉露出网页来源的解决办法:将document的touchmove事件禁止掉 //禁止页面拖动 document.addEventListener('touchmove', functio ...
- Python优秀开源项目Rich源码解析
这篇文章对优秀的开源项目Rich的源码进行解析,OMG,盘他.为什么建议阅读源码,有两个原因,第一,单纯学语言很难在实践中灵活应用,通过阅读源码可以看到每个知识点的运用场景,印象会更深,以后写代码的时 ...
- Numerical Sequence (Hard vision) 题解
The only difference between the easy and the hard versions is the maximum value of \(k\). You are gi ...
- 31道Java核心面试题,一次性打包送给你
先看再点赞,给自己一点思考的时间,微信搜索[沉默王二]关注这个靠才华苟且的程序员.本文 GitHub github.com/itwanger 已收录,里面还有一线大厂整理的面试题,以及我的系列文章. ...
- zsh切换bash提示chsh: no changes made问题
前提纪要:1.我们都知道mac有默认bash工具,在下载zsh后,把一切都配置好后,输入切换命令:chsh - s /bin/zsh ,总是提示 chsh: no changes made错误.那我我 ...
- 消息队列-一篇读懂rabbitmq(生命周期,confirm模式,延迟队列,集群)
什么是消息队列? 就是生产者生产一条消息,发送到这个rabbitmq,消费者连接rabbitmq并且进行消费,生产者和消费者并需要知道对方是如何工作的,从而实现程序之间的解耦,异步和削峰,这也就是消息 ...
- web CSS3 实现3D动态翻牌效果
使用纯CSS3 实现翻牌效果 需要注意要给子盒子使用绝对定位,这样两个盒子可以完全重合在一起,需要给父盒子一个 transform-style: preserve-3d;让子盒子翻转时保持3D效果, ...
- 大话深度学习:B站Up主麦叔教你零代码实现图像分类神经网络
之前,我在B站发布了“大话神经网络,10行代码不调包,听不懂你打我!”的视频后,因为简单易懂受到了很多小伙伴的喜欢! 但也有小伙伴直呼不够过瘾,因为大话神经网络只有4个神经元. 也有小伙伴问不写代码, ...
- centos7.6静默安装oracle 11G RAC
环境介绍, esxi6.0 ,VMware vSphere Client6.0 linux 版本Centos7.6(最小化安装) Oracle 版本 oracle 11g 11.2.0.4 虚拟化环境 ...
- nginx: command not found
nginx 正常启动,可以访问服务器地址:welcome to nginx 使用nginx -t 等命令时 报错:nginx: command not found 这是环境变量未配置 配置环境变量 v ...