LOJ#2134 小园丁与老司机
我的妈呀,这码农神题......
第一问是个DP,要记录方案。先把纵向的转移建图。发现可以按照y坐标来划分阶段,每一层vector存一下,用前后缀最大值来转移。
第二问考虑所有可能成为最优方案的边。从终点倒推可以保证每条边都能到起点,而从起点出发就不一定能保证。这些边拿去网络流建图,然后最小流。
注意第二问找边的时候,每一层的点其实可以视作两个,经过同层转移的和未经过的。这两者不可混为一谈。
最小流先跑S -> T然后t -> s退流的话,要用当前弧优化,否则会被最后一个数据卡成n²。
#include <bits/stdc++.h> const int N = , INF = 0x7f7f7f7f; struct Node {
int x, y, id;
inline bool operator <(const Node &w) const {
if(y != w.y) return y < w.y;
return x < w.x;
}
}node[N]; inline void read(int &x) {
x = ;
char c = getchar();
bool f = ;
while(c < '' || c > '') {
if(c == '-') f = ;
c = getchar();
}
while(c >= '' && c <= '') {
x = x * + c - ;
c = getchar();
}
if(f) x = (~x) + ;
return;
} struct Edge {
int nex, v;
}edge[N << ]; int tp; int n, X[N << ], xx, bin[N << ], e[N], fr1[N], fr2[N], fr_l[N], fr_r[N], large_l[N], large_r[N], f[N], ff[N];
bool visit[N], visit2[N];
std::vector<int> v[N << ]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void out(int x, int flag) {
if(!node[x].id) return;
if(flag == ) {
out(fr1[x], );
}
else {
out(fr2[x], );
int y = fr2[x], u = node[y].y;
if(y == x) {
printf("%d ", node[x].id);
}
else if(node[y].x > node[x].x) {
for(int i = ; i < (int)(v[u].size()); i++) {
if(node[v[u][i]].x >= node[y].x) {
printf("%d ", node[v[u][i]].id);
}
}
for(int i = v[u].size() - ; i >= ; i--) {
int temp = node[v[u][i]].x;
if(temp < node[y].x && temp >= node[x].x) {
printf("%d ", node[v[u][i]].id);
}
}
}
else {
for(int i = v[u].size() - ; i >= ; i--) {
if(node[v[u][i]].x <= node[y].x) {
printf("%d ", node[v[u][i]].id);
}
}
for(int i = ; i < (int)(v[u].size()); i++) {
int temp = node[v[u][i]].x;
if(temp > node[y].x && temp <= node[x].x) {
printf("%d ", node[v[u][i]].id);
}
}
}
}
return;
} namespace fl {
struct Edge {
int nex, v, c;
Edge(int Nex = , int V = , int C = ) {
nex = Nex;
v = V;
c = C;
}
}edge[]; int tp = ;
int e[N], vis[N], in[N], d[N], vis2[N], cur[N];
std::queue<int> Q;
inline void add(int x, int y, int z) {
edge[++tp] = Edge(e[x], y, z);
e[x] = tp;
edge[++tp] = Edge(e[y], x, );
e[y] = tp;
return;
}
inline void Add(int x, int y) {
/// x -> y [1, INF]
vis2[x] = vis2[y] = ;
add(x, y, N);
in[y]++;
in[x]--;
return;
}
inline bool BFS(int s, int t) {
static int Time = ; Time++;
vis[s] = Time;
d[s] = ;
Q.push(s);
while(!Q.empty()) {
int x = Q.front();
Q.pop();
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(vis[y] != Time && edge[i].c) {
vis[y] = Time;
d[y] = d[x] + ;
Q.push(y);
}
}
}
return vis[t] == Time;
}
int DFS(int x, int t, int maxF) {
if(x == t) return maxF;
int ans = ;
for(int i = cur[x] ? cur[x] : e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(!edge[i].c || d[y] != d[x] + ) {
continue;
}
int temp = DFS(y, t, std::min(maxF - ans, edge[i].c));
if(!temp) d[y] = INF;
ans += temp;
edge[i].c -= temp;
edge[i ^ ].c += temp;
if(ans == maxF) break;
cur[x] = i;
}
return ans;
}
inline int dinic(int s, int t) {
int ans = ;
while(BFS(s, t)) {
memset(cur, , sizeof(cur));
ans += DFS(s, t, INF);
}
return ans;
}
inline void solve() {
int s = N - , t = N - , S = N - , T = N - ;
for(int i = ; i <= n; i++) {
if(!vis2[i]) continue;
add(s, i, N);
add(i, t, N);
}
int now = tp;
add(t, s, INF);
for(int i = ; i <= n; i++) {
if(in[i] > ) {
add(S, i, in[i]);
}
else if(in[i] < ) {
add(i, T, -in[i]);
}
}
int ans;
dinic(S, T);
ans = edge[now + ].c;
for(int i = now + ; i <= tp; i++) edge[i].c = ;
ans -= dinic(t, s);
printf("%d\n", ans);
return;
}
} int main() {
read(n);
for(int i = ; i <= n; i++) {
read(node[i].x); read(node[i].y);
node[i].id = i;
X[++xx] = node[i].x;
X[++xx] = node[i].y;
X[++xx] = node[i].x + node[i].y;
X[++xx] = node[i].x - node[i].y;
}
++n; ++xx; /// the Node O
std::sort(node + , node + n + );
std::sort(X + , X + xx + );
xx = std::unique(X + , X + xx + ) - X - ;
for(int i = ; i <= n; i++) {
int temp = std::lower_bound(X + , X + xx + , node[i].x + node[i].y) - X;
if(bin[temp]) {
add(bin[temp], i);
}
bin[temp] = i;
}
memset(bin + , , xx * sizeof(int));
for(int i = ; i <= n; i++) {
int temp = std::lower_bound(X + , X + xx + , node[i].x - node[i].y) - X;
if(bin[temp]) {
add(bin[temp], i);
}
bin[temp] = i;
}
memset(bin + , , xx * sizeof(int));
for(int i = ; i <= n; i++) {
node[i].x = std::lower_bound(X + , X + xx + , node[i].x) - X;
node[i].y = std::lower_bound(X + , X + xx + , node[i].y) - X;
}
for(int i = ; i <= n; i++) {
if(bin[node[i].x]) {
add(bin[node[i].x], i);
}
bin[node[i].x] = i;
v[node[i].y].push_back(i);
}
/// Build Graph 1 Over
memset(f, ~0x3f, sizeof(f));
f[] = ;
for(int u = ; u <= xx; u++) {
if(!v[u].size()) continue;
int len = v[u].size();
for(int i = ; i < len; i++) {
int x = v[u][i];
ff[x] = f[x];
fr2[x] = x;
}
/// trans in row
for(int i = ; i < len; i++) {
int x = v[u][i];
if(i && f[x] < large_l[i - ]) {
large_l[i] = large_l[i - ];
fr_l[i] = fr_l[i - ];
}
else {
large_l[i] = f[x];
fr_l[i] = x;
}
}
for(int i = len - ; i >= ; i--) {
int x = v[u][i];
if(i < len - && f[x] < large_r[i + ]) {
large_r[i] = large_r[i + ];
fr_r[i] = fr_r[i + ];
}
else {
large_r[i] = f[x];
fr_r[i] = x;
}
}
for(int i = ; i < len; i++) {
int x = v[u][i];
if(i < len - && f[x] < large_r[i + ] + len - i - ) {
f[x] = large_r[i + ] + len - i - ;
fr2[x] = fr_r[i + ];
}
if(i && f[x] < large_l[i - ] + i) {
f[x] = large_l[i - ] + i;
fr2[x] = fr_l[i - ];
}
}
/// trans in cross / other
for(int i = ; i < len; i++) {
int x = v[u][i];
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(f[y] < f[x] + ) {
f[y] = f[x] + ;
fr1[y] = x;
}
}
}
}
/// DP OVER
int large_val = -INF, ans_pos = ;
for(int i = ; i <= n; i++) {
if(large_val < f[i]) {
large_val = f[i];
ans_pos = i;
}
}
printf("%d\n", large_val);
out(ans_pos, );
/// Out OVER
for(int i = ; i <= n; i++) {
if(f[i] == large_val) visit2[i] = ;
if(ff[i] == large_val) visit[i] = ;
}
for(int u = xx; u >= ; u--) {
if(!v[u].size()) continue;
int len = v[u].size();
/// build Flow Graph (this -> up)
for(int i = ; i < len; i++) {
int x = v[u][i];
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(visit[y] && ff[y] == f[x] + ) {
visit2[x] = ;
fl::Add(x, y);
}
}
if(visit2[x] && f[x] == ff[x]) {
visit[x] = ;
}
}
/// Find Edge in row (update)
for(int j = ; j < len; j++) {
int y = v[u][j];
if(!visit2[y]) continue;
for(int i = ; i < len; i++) {
int x = v[u][i];
if(visit[x]) continue;
/// x -> y
if(node[x].x < node[y].x && f[y] == ff[x] + j) {
visit[x] = ;
}
else if(node[y].x < node[x].x && f[y] == ff[x] + len - j - ) {
visit[x] = ;
}
}
}
}
puts("");
/// Build Flow Over
fl::solve();
return ;
}
AC代码
10k还行
LOJ#2134 小园丁与老司机的更多相关文章
- [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机
[LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...
- [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】[Noi2015]小园丁与老司机 DP+最小流
[BZOJ2839][Noi2015]小园丁与老司机 Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2, ...
- 「NOI2015」小园丁与老司机
「NOI2015」小园丁与老司机 要不是这道码农题,去年就补完了NOI2015,其实两问都比较simple,但是写起来很恶心. 先解决第一问,记 \(dp[i]\) 表示老司机到达第 \(i\) 棵树 ...
- luogu P2304 [NOI2015]小园丁与老司机 dp 上下界网络流
LINK:小园丁与老司机 苦心人 天不负 卧薪尝胆 三千越甲可吞吴 AC的刹那 真的是泪目啊 很久以前就写了 当时记得特别清楚 写到肚子疼.. 调到胳膊疼.. ex到根不不想看的程度. 当时wa了 一 ...
- 【洛谷2304_LOJ2134】[NOI2015]小园丁与老司机(动态规划_网络流)
题目: 洛谷 2304 LOJ 2134 (LOJ 上每个测试点有部分分) 写了快一天 -- 好菜啊 分析: 毒瘤二合一题 -- 注意本题(及本文)使用 \(x\) 向右,\(y\) 向上的「数学坐标 ...
- [BZOJ]4200: [Noi2015]小园丁与老司机
Time Limit: 20 Sec Memory Limit: 512 MBSec Special Judge Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维 ...
随机推荐
- easyUI定区关联快递员js代码
easyUI定区关联快递员js代码: <script type="text/javascript"> $.fn.serializeJson=function(){ va ...
- Day 4-9 subprocess模块
我们经常需要通过Python去执行一条系统命令或脚本,系统的shell命令是独立于你的python进程之外的,每执行一条命令,就是发起一个新进程,通过python调用系统命令或脚本的模块在python ...
- 用Python来操作redis 以及在Django中使用redis
什么是Redis? Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure server). Redis的键值可以包 ...
- 莫烦keras学习自修第四天【分类问题】
1.代码实战 #!/usr/bin/env python #! _*_ coding:UTF-8 _*_ # 导入numpy import numpy as np np.random.seed(133 ...
- windows下ping端口
上图的操作完成以后 进入dos控制台 输入telnet ip地址 端口号 回车 标识已ping通 ping不通是这种提示
- Redux学习(2) ----- 异步和中间件
Redux中间件,其实就是一个函数, 当我们发送一个action的时候,先经过它,我们就可以对action进行处理,然后再发送action到达reducer, 改变状态,这时我们就可以在中间件中,对a ...
- mysql出现ERROR1698(28000):Access denied for user root@localhost错误解决方法
我的操作系统是ubuntu18.04,以下是我的mysql版本: 安装完成后,登录mysql的时候就出现了如下错误: 因为安装的过程中没让设置密码,可能密码为空,但无论如何都进不去mysql. 那么该 ...
- excel导入、导出
http://blog.csdn.net/cjh200102/article/details/12557599 NPOI 工作本HSSFWorkbook 构造方法,无参表示创建一个新的工作本,可以接收 ...
- BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...
- Codeforces Round #426 Div. 1
A:考虑每个质因子,显然要求次数之和是3的倍数,且次数之差的两倍不小于较小的次数.对于第一个要求,乘起来看开三次方是否是整数即可.第二个取gcd,两个数分别除掉gcd,之后看两个数的剩余部分是否都能被 ...