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 负责看管一片田野,田野可以看作一个二维 ...
随机推荐
- 手机端图像编辑上传-cropper
编辑头像,实现相册,照像功能,并能缩放裁剪功能,可自定义UI,引用'cropper.js', 'exif.js' /*初始化裁剪插件*/ var screenWidth = $(window).wid ...
- docker遇到的问题以及docker 操作镜像的基本操作
root@localhost ~]# systemctl status docker.service ● docker.service - Docker Application Container E ...
- hive 查询注意问题
1)对于hive内置的列,不是自己建的,在查询的时候需要添加反引号` 比如:`_mt_message`,别在这里犯错误, (2)南京的_mt_message是json的格式,所以可以直接使用:get_ ...
- TensorFlow总结
第一 基础 1. 定义变量 #定义维度为[2,3], 平均值为·1, 标准差为1,类型为float32,名称为w1的服从正态分布的变量 w1 = tf.Variable(tf.random_norma ...
- Lodop“对象不支持SET__LICENSES属性或方法”SET__LICENSES is not a function”
Lodop中的方法如果书写错误,就会报错:“对象不支持XXX属性或方法”调试JS会报错”SET__LICENSES is not a function” LODOP.SET_LICENSES是加注册语 ...
- css 引用自定义图标
1.进入阿里图标库搜索需要的图标(搜索“图标"是全部的) 2.选择需要的图标 下载 下载svg 格式 进入https://icomoon.io/ css引用库 解压下载的压缩包 ok ...
- 【python练习题】程序1
#题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? count = 0 for i in range(1,5): for j in range(1,5): for k ...
- hdu-1176(dp)
解题思路:用dp做的,dp[i][j]表示在i时刻,j点的最大馅饼.a[i][j]表示在i这个时刻j点同时掉落的馅饼: 每个点除了0和10之外,都有三种状态: 1.没有移动,这样值就为dp[i][j] ...
- BZOJ3144[Hnoi2013]切糕——最小割
题目描述 输入 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤ ...
- ysg 一道简单的数论题
先声明一点,这个题从一套模拟题中选取出来,所以可能会冒犯到原出题人.请谅解 题干: ysg,yxy,azw 三人正在刷题. 他们每做一题的时间都是一个有理数. 如果在某一时刻,三人同时做完一道 题,那 ...