本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:UOJ132

正解:DP+上下界网络流

解题报告:

  第一、二问是一起的,DP一遍可以解决。

  具体而言,f[i]记录到达i的最优值,g[i]记录前驱结点。

  按y分层,不同层之间直接转,左上右上的一条直线上的点x、y坐标的和或者差相等,map保存最后的值(写转入会方便一些)。

  同一层之间有一点麻烦,考虑一定是从一个点走进这一层之后,把一边的所有点遍历完之后再走向另一边,从某个点走出这一层。

  这个用前缀和后缀最大值维护一下就可以了,输出方案的时候就记录一下这个点是从同一层还是从之前的层转移过来的,就可以确定经过的点了。

  第三问的话,我们可以通过前两问,得到每个点的f,对于可能出现在最优解上的边,我们都拎出来,然后建图。

  考虑题目要求我们什么。因为每条边都至少要被经过一次,就可以理解成求下界为1上界为inf的最小流。

  就变成了有上下界的最小流问题了,这道题的建图方式是:超级源点S向所有in[i]-out[i]>0的点连容量为in[i]-out[i]的边,所有in[i]-out[i]<0的点向超级汇点T连容量为out[i]-in[i]的边,原边容量为inf。

  跑一遍最大流,最后用满流-最大流即为所求。

  

  ps:我开始是用vector存下所有的可行转移,然后调了一个晚上调不出,小点都过了,大点有的AC有的WA...

    今天早上一来机房,痛下决心,task3重写!

    换成了重新DP一遍,倒着做一遍,再正着连边,这样做就好调很多了...

    建议:不要在脑子不清醒的时候写这道题,这会让你怀疑自己长了一个假脑子...  

      如果发现自己调试不出来了,建议换一种写法或者重写一遍。祝你身体健康

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
const int MAXN = 50011;
const int MAXM = 300011;
const int MOD = 300007;
const int inf = (1<<29);
int n,f[MAXN],g[MAXN],from[MAXN],from2[MAXN],ans,dui[MAXN],belong[MAXN],le[MAXN],ri[MAXN],ycnt;
int ecnt,first[MAXN],in[MAXN],hcnt,S,T,deep[MAXN],tot,dp[MAXN];
bool same[MAXN],vis[MAXN];
map<int,bool>mp[MAXN];
struct node{ int x,y,id; }a[MAXN];
struct edge{ int to,next,f; }e[MAXM];
struct bian{ int x,y; }b[MAXM];
inline bool cmpy(node q,node qq){ if(q.y==qq.y) return q.x<qq.x; return q.y<qq.y; }
inline void link(int x,int y,int z){ e[++ecnt].next=first[x]; first[x]=ecnt; e[ecnt].to=y; e[ecnt].f=z;e[++ecnt].next=first[y]; first[y]=ecnt; e[ecnt].to=x; e[ecnt].f=0;
}inline int getint(){int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}struct Hash{//哈希表查询直线上的最近的点int ecnt,first[MOD+12],to[100011],next[100011],w[100011];inline void clear(){ ecnt=0; memset(first,0,sizeof(first)); }inline int query(int x){ int cc=x%MOD; cc+=MOD; cc%=MOD; for(int i=first[cc];i;i=next[i]) if(to[i]==x) return w[i]; return -1; }inline void insert(int x,int val) {int cc=x%MOD; cc+=MOD; cc%=MOD;  for(int i=first[cc];i;i=next[i]) if(to[i]==x) { w[i]=val; return ; }next[++ecnt]=first[cc]; first[cc]=ecnt; to[ecnt]=x; w[ecnt]=val;}
}t1,t2,t3;inline void DP(){//第一问输出最优值int l,r,last,pos; t1.insert(0,0); t2.insert(0,0); t3.insert(0,0);for(int i=1;i<=n;i++) f[i]=g[i]=-inf;for(int i=1;i<=n;i=r+1) {l=r=i; while(r<n && a[r+1].y==a[l].y) r++;ycnt++; le[ycnt]=l; ri[ycnt]=r; for(int j=l;j<=r;j++) belong[j]=ycnt;//转入for(int j=l;j<=r;j++) {last=t1.query(a[j].x+a[j].y); t1.insert(a[j].x+a[j].y,j); if(last==-1) continue;if(f[last]+1>f[j]) { f[j]=f[last]+1; from[j]=last; }}for(int j=l;j<=r;j++) {last=t2.query(a[j].x-a[j].y); t2.insert(a[j].x-a[j].y,j); if(last==-1) continue;if(f[last]+1>f[j]) { f[j]=f[last]+1; from[j]=last; }}for(int j=l;j<=r;j++) {last=t3.query(a[j].x);  t3.insert(a[j].x,j); if(last==-1) continue;if(f[last]+1>f[j]) { f[j]=f[last]+1; from[j]=last; }}//同层之间的转移,一定是从pos走入,然后走到边界,再往回走,从某个点走出pos=l;//存储最大的位置,前缀maxfor(int j=l+1;j<=r;j++) {if(f[j-1]>f[pos]) pos=j-1;if(f[pos]+j-l>g[j]) { g[j]=f[pos]+j-l; from2[j]=pos; }}pos=r;//后缀maxfor(int j=r-1;j>=l;j--) {if(f[j+1]>f[pos]) pos=j+1;if(f[pos]+r-j>g[j]) { g[j]=f[pos]+r-j; from2[j]=pos; }}for(int j=l;j<=r;j++) if(f[j]<g[j]) { f[j]=g[j]; same[j]=1; }//打上同层转移标记}ans=-inf; for(int i=1;i<=n;i++) ans=max(ans,f[i]);if(ans<0) { printf("0\n\n0"); exit(0); }printf("%d\n",ans);
}inline void Print(){int pos=1,top=0; for(int i=1;i<=n;i++) if(f[i]>f[pos]) pos=i;while(pos) {//逆序输出if(same[pos]) {if(from2[pos]<pos) {for(int i=pos;i>from2[pos];i--) dui[++top]=i;for(int i=le[belong[pos]];i<=from2[pos];i++) dui[++top]=i;}else{for(int i=pos;i<from2[pos];i++) dui[++top]=i;for(int i=ri[belong[pos]];i>=from2[pos];i--) dui[++top]=i;}pos=from2[pos];pos=from[pos];}else {    dui[++top]=pos;  pos=from[pos]; }}for(int i=top;i>=1;i--) printf("%d ",a[dui[i]].id); puts("");
}inline void DP2(){//逆序跑一遍,方便连边for(int i=0;i<=n;i++) if(f[i]==ans) dp[i]=1; else dp[i]=-inf;for(int i=0;i<=n;i++) g[i]=-inf;t1.clear(); t2.clear(); t3.clear(); int l,r,last,pos; dp[0]=ans;for(int i=n;i>=1;i=l-1) {l=r=i; while(a[l-1].y==a[r].y) l--;for(int j=l;j<=r;j++) {last=t1.query(a[j].x+a[j].y); t1.insert(a[j].x+a[j].y,j); if(last==-1) continue;if(dp[last]+1>dp[j]) { dp[j]=dp[last]+1; from[j]=last; }}for(int j=l;j<=r;j++) {last=t2.query(a[j].x-a[j].y); t2.insert(a[j].x-a[j].y,j); if(last==-1) continue;if(dp[last]+1>dp[j]) { dp[j]=dp[last]+1; from[j]=last; }}for(int j=l;j<=r;j++) {last=t3.query(a[j].x);  t3.insert(a[j].x,j); if(last==-1) continue;if(dp[last]+1>dp[j]) { dp[j]=dp[last]+1; from[j]=last; }}pos=l;for(int j=l+1;j<=r;j++) {if(dp[pos]+r-pos<dp[j-1]+r-j+1) pos=j-1;if(dp[pos]+r-pos>g[j]) g[j]=dp[pos]+r-pos;}pos=r;for(int j=r-1;j>=l;j--) {if(dp[pos]+pos-l<dp[j+1]+j+1-l) pos=j+1;if(dp[pos]+pos-l>g[j]) g[j]=dp[pos]+pos-l;}for(int j=l;j<=r;j++) dp[j]=max(dp[j],g[j]);}
}inline void build(){//建图t1.clear(); t2.clear(); t3.clear(); a[0].x=a[0].y=0; int l,r,last;for(int i=n;i>=0;i=l-1) {l=le[belong[i]]; r=ri[belong[i]];for(int j=l;j<=r;j++) {last=t1.query(a[j].x+a[j].y); t1.insert(a[j].x+a[j].y,j); if(last==-1) continue;if(dp[last]+f[j]==ans) b[++hcnt].x=j,b[hcnt].y=last;}for(int j=l;j<=r;j++) {last=t2.query(a[j].x-a[j].y); t2.insert(a[j].x-a[j].y,j); if(last==-1) continue;if(dp[last]+f[j]==ans) b[++hcnt].x=j,b[hcnt].y=last;}for(int j=l;j<=r;j++) {last=t3.query(a[j].x); t3.insert(a[j].x,j); if(last==-1) continue;if(dp[last]+f[j]==ans) b[++hcnt].x=j,b[hcnt].y=last;}}ecnt=1; S=n+1; T=S+1;for(int i=1;i<=hcnt;i++) { in[b[i].x]--; in[b[i].y]++; link(b[i].x,b[i].y,inf); }for(int i=1;i<=n;i++) {if(in[i]>0) link(S,i,in[i]),tot+=in[i];else if(in[i]<0) link(i,T,-in[i]);}
}inline bool bfs(){int head,tail,u; head=tail=0;for(int i=1;i<=T;i++) deep[i]=-1; deep[S]=0; dui[++tail]=S;while(head<tail) {u=dui[++head];for(int i=first[u];i;i=e[i].next) {if(e[i].f==0) continue;   int v=e[i].to; if(deep[v]!=-1) continue;deep[v]=deep[u]+1; dui[++tail]=v;}}if(deep[T]==-1) return false;return true;
}inline int dinic(int x,int remain){if(x==T || remain==0) return remain;int flow=0,ff;for(int i=first[x];i;i=e[i].next) {if(e[i].f==0) continue; int v=e[i].to;if(deep[v]!=deep[x]+1) continue;ff=dinic(v,min(remain,e[i].f));if(ff==0) deep[v]=-1;else {  flow+=ff; remain-=ff;e[i].f-=ff; e[i^1].f+=ff;if(remain==0) return flow;}}return flow;
}inline void work(){n=getint(); for(int i=1;i<=n;i++) { a[i].x=getint(); a[i].y=getint(); a[i].id=i; }sort(a+1,a+n+1,cmpy); a[0].x=a[0].y=a[n+1].x=a[n+1].y=-inf;DP();Print();DP2();build();while(bfs()) tot-=dinic(S,inf);printf("%d",tot);
}int main()
{work();return 0;
}

  

转载于:https://www.cnblogs.com/ljh2000-jump/p/6408329.html

UOJ132 【NOI2015】小园丁与老司机相关推荐

  1. P2304 [NOI2015] 小园丁与老司机(网络流/上下界网络流)

    P2304 [NOI2015] 小园丁与老司机 平面上有n个点,每次可以向左.右.上.左上45度.右上45度移动,然后直线移动到达第一个没有到过的点,如果没有这样的点就不能移动,求解一条最长路,然后求 ...

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

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

  3. 提高千倍效率的35个编码小技巧,老司机带你飞!

    点击关注公众号,实用技术文章及时了解 来源:henleylee.github.io/posts/2019/a780fcc1.html 前言 代码优化 ,一个很重要的课题.可能有些人觉得没用,一些细小的 ...

  4. mysql入门到跑路_Mysql入门二十小题(DBA老司机带你删库到跑路)2018.11.26

    1. 请介绍数据库管理系统的种类及代表产品 RDBMS: mysql oracle mssql NoSQL: redis  mongoab  memcache 2. 请简述数据库管理系统的作用 数据存 ...

  5. oracle从删库到跑路,Mysql入门二十小题(DBA老司机带你删库到跑路)2018.11.26

    1. 请介绍数据库管理系统的种类及代表产品 RDBMS: mysql oracle mssql NoSQL: redis  mongoab  memcache 2. 请简述数据库管理系统的作用 数据存 ...

  6. 年薪30W的软件测试“老司机”工作经验

    这几天,新入职的小MM提议"老司机"们把自己这些年的软件测试工作经验跟大家分享一下,让新同学学习学习,利用空闲时间我整理了一些,可能不全,勉强看看,这也算是对自己这些年的工作总结. ...

  7. 【新梦想学员干货】必看!年薪30W的软件测试“老司机”工作经验。

    这几天,新入职的小MM提议"老司机"们把自己这些年的软件测试工作经验跟大家分享一下,让新同学学习学习,利用空闲时间我整理了一些,可能不全,勉强看看,这也算是对自己这些年的工作总结. ...

  8. 名悦集团:开车从不追尾,老司机分享驾驶避免事故小知识

    听交通广播,我们几乎每天都能听到高速路上,高架桥上,上班路上发生追尾事故,有时候是个平常的上下班高峰期.很多人会纳闷,车开的好好的,怎么就会发生追尾事故呢.开车在路上,难免会有磕磕碰碰.道路千万条,安 ...

  9. 老司机都在用的浏览器,体积小功能齐全,直呼内行

    现在市面上的浏览器简直是多不胜数,虽然数量多,但是好用的并不多.尤其是某些大厂的浏览器,无用的功能越来越多,越来越臃肿,体积也越来越大,使用体验还不好,有时候甚至不如一些小众浏览器.今天给大家安利2款 ...

  10. 视频教程-老司机讲前端之微信小程序开发成语消消乐游戏视频课程-微信开发

    老司机讲前端之微信小程序开发成语消消乐游戏视频课程 中国实战派HTML5培训第一人,微软技术讲师,曾任百合网技术总监,博看文思HTML5总监.陶国荣长期致力于HTML5.JavaScript.CSS3 ...

最新文章

  1. string 中的offset_Kafka+Spark Streaming管理offset的两种方法
  2. smartqq java撤回_基于nodejs的http模块通过smartqq实现自动收发qq消息的程序
  3. 2010.7.27 OnDraw与OnPaint有什么区别
  4. 使用Visual Studio.net调试javascript最方便的方法
  5. python编程从入门到实战1-3章
  6. 深圳数据分析认证(CPDA)含金量怎么样?
  7. jzxx1107【入门】字符图形6-星号倒三角
  8. cocos2d 物理平抛,斜抛运动
  9. 1041: 数列求和2 C语言
  10. 2019中兴通讯软件开发岗c/c++方向(笔试+面试)总结
  11. NSGA-II中“支配”的概念
  12. dell计算机的硬盘如何分区,戴尔电脑分盘怎么分区
  13. 【老生谈算法】matlabAP近邻传播聚类算法源码——聚类算法
  14. 202001 ora-00922: missing or invalid option 密码修改提示;“ORA-28007: the password cannot be reused”解决
  15. 商家或企业做小红书种草推广具体有哪些好处?
  16. 软件设计师9--正则表达式
  17. 强制页面运行于IE8模式下
  18. vs code-live server-保存文件后浏览器自动刷新页面
  19. 宝尊:名企淘宝专营店的幕后推手
  20. 免费对接第三方快递物流单号识别信息查询api接口

热门文章

  1. manacher魔板
  2. 【内存】ECC内存简介
  3. blog post list.html,Zblog模板修改和Zblog各模板代表的含义
  4. java游戏少年张三丰的原代码_RPG大作《少年张三丰》完美游戏攻略
  5. 网络安全----数字签名与数字证书
  6. 网站受到流量攻击怎么办
  7. 水平面:篡命铜钱の2
  8. USB3.0 HUB方案之VL817-Q7
  9. java裂变_微信现金红包单一红包、裂变红包(Java版)
  10. Win7网络和共享中心 依赖服务或组无法启动 解决办法