绝地反击

题目背景:

5.14 模拟 JSOI2018D1T3

分析:计算几何 + 网络流 + 二分 + 网络流退流

又是我不会的新姿势,首先我们考虑如何暴力,对于最优的时间,我们可以肯定,一定有一个飞船是恰好在这个时间到了对应坐标,而没有任何停留,否则一定可以更优,那么我们二分最大时间,然后枚举每一条飞船作为最晚到达的那一个,然后就可以确定对应的位置,然后跑一遍二分图匹配即可,这样做的话普通写大概有50 ~ 60,加上一些特判和一些剪枝大概能够有90左右,当然,这个结果是loj得到的。

时间复杂度:O(n7/2logn~ n4logn),据说用HK可以卡过去?

Source:

/*created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>inline char read() {static const int IN_LEN = 1024 * 1024;static char buf[IN_LEN], *s, *t;if (s == t) {t = (s = buf) + fread(buf, 1, IN_LEN, stdin);if (s == t) return -1;}return *s++;
}///*
template<class T>
inline void R(T &x) {static char c;static bool iosig;for (c = read(), iosig = false; !isdigit(c); c = read()) {if (c == -1) return ;if (c == '-') iosig = true; }for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;
}
//*/const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;*oh++ = c;
}template<class T>
inline void W(T x) {static int buf[30], cnt;if (x == 0) write_char('0');else {if (x < 0) write_char('-'), x = -x;for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;while (cnt) write_char(buf[cnt--]);}
}inline void flush() {for (int i = 0; i <= 10; ++i) std::cout << obuf[i];std::cout << '\n';fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}/*
template<class T>
inline void R(T &x) {static char c;static bool iosig;for (c = getchar(), iosig = false; !isdigit(c); c = getchar())if (c == '-') iosig = true; for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;
}
//*/const int MAXN = 400 + 10;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int INF = MAXN;struct node {int to, w, rev;node() {}node(int to, int w, int rev) : to(to), w(w), rev(rev) {}
} ;std::vector<node> edge[MAXN << 1];
int dis[MAXN], temp[MAXN];
inline void add_edge(int x, int y, int w) {edge[x].push_back(node(y, w, edge[y].size()));edge[y].push_back(node(x, 0, edge[x].size() - 1));
}inline bool bfs(int s, int t) {static std::queue<int> q;memset(dis, -1, sizeof(int) * (t + 5));memset(temp, 0, sizeof(int) * (t + 5));dis[s] = 0, q.push(s);while (!q.empty()) {int cur = q.front();q.pop();for (int p = 0; p < edge[cur].size(); ++p) {node *e = &edge[cur][p];if (e->w && dis[e->to] == -1) dis[e->to] = dis[cur] + 1, q.push(e->to);}}return dis[t] != -1;
}inline int dfs(int cur, int low, int t) {if (cur == t) return low;int delta = 0;for (int &p = temp[cur]; p < edge[cur].size(); ++p) {node *e = &edge[cur][p];if (e->w && dis[e->to] == dis[cur] + 1) {int ret = dfs(e->to, std::min(low - delta, e->w), t);e->w -= ret, edge[e->to][e->rev].w += ret;if ((delta += ret) == low) break ;}}return delta;
}inline int dinic(int s, int t) {int ans = 0, ret = 0;while (bfs(s, t)) do ret = dfs(s, INF, t); while (ans += ret, ret);return ans;
}struct point {double x, y;point() {}point(double x, double y) : x(x), y(y) {}inline point operator + (const point &a) const {return point(x + a.x, y + a.y);}inline point operator - (const point &a) const {return point(x - a.x, y - a.y);}inline point operator / (const double a) const {return point(x / a, y / a);}inline point operator * (const double a) const {return point(x * a, y * a);}inline double dis() {return sqrt(x * x + y * y);}inline double dis2() {return x * x + y * y;}inline point rotate(double ang) {double cos_a = cos(ang), sin_a = sin(ang);return point(x * cos_a - y * sin_a, x * sin_a + y * cos_a);}
} p[MAXN], st[MAXN];int n, r, x, y;inline point get_pos(point p, double dis, double flag) {double a = dis, b = r, c = p.dis();double cos_a = (b * b + c * c - a * a) / 2.00 / b / c;point cur = p / c * r;return cur = cur.rotate(flag * acos(cos_a)), cur;
}inline bool check(point st, int id, double max) {int s = 0, t = 2 * n + 1;for (int i = s; i <= t; ++i) edge[i].clear();for (int i = 1; i < n; ++i) {st = st.rotate(2.0 * PI / n);int cc = 0;for (int j = 1; j <= n; ++j) if (j != id && (p[j] - st).dis2() <= max * max) add_edge(j, i + n, 1), cc++;if (cc == 0) return false;}for (int i = 1; i <= n; ++i) if (i != id) add_edge(s, i, 1);for (int i = 1; i < n; ++i) add_edge(i + n, t, 1);return (dinic(s, t) == n - 1);
}inline bool check(double x) {for (int i = 1; i <= n; ++i) {if (x < p[i].dis() - r || x < r - p[i].dis()) return false;if (x > p[i].dis() + r) {st[i] = point(INF, INF);continue ;}st[i] = get_pos(p[i], x, 1);}for (int i = 1; i <= n; ++i)if (st[i].x != INF && check(st[i], i, x)) return true;return false;
}inline void solve() {R(n), R(r);for (int i = 1; i <= n; ++i) R(x), R(y), p[i] = point(x, y);std::random_shuffle(p + 1, p + n + 1);double l = -eps, r = 0;for (int i = 1; i <= n; ++i) r = std::max(p[i].dis() + ::r, r);int cnt = 0;while (l + eps < r) {double mid = (l + r) / 2;check(mid) ? r = mid : l = mid;}printf("%0.8f", r);
}int main() {// freopen("in.in", "r", stdin);// freopen("fleet.out", "w", stdout);solve();return 0;
}

考虑如何优化复杂度,我们发现如果把x轴正半轴上的(r, 0)当做其中一个坐标,那么所有的可行方案与这个方案的角度都不超过2pi / n,那么我们考虑维护逆时针进行偏转的过程,我们发现,如果一开始先将(r, 0)定位为1号点,那么随着偏转,每一个点原有的可行匹配点会在某一时刻减少一个,也会在某一时刻增加一个,那么我们可以将每一种操作的偏转角度记录下来,然后将操作排序,显然操作总个数是O(n)的,每一次操作相当于从网络流建图中删掉一条边,或者增加一条边,我们只需要将这个流量退掉,或者加上就可以了,因为是二分图,所以一次只会影响三条边,还是很轻松的,因为流量改变只有一,所以一次退流或者加边的复杂度都应该是O(n + m)的,那么总复杂度都是O(n3logn)。

Source:

/*created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <deque>
#include <iterator>
#include <map>inline char read() {static const int IN_LEN = 1024 * 1024;static char buf[IN_LEN], *s, *t;if (s == t) {t = (s = buf) + fread(buf, 1, IN_LEN, stdin);if (s == t) return -1;}return *s++;
}// /*
template<class T>
inline void R(T &x) {static char c;static bool iosig;for (c = read(), iosig = false; !isdigit(c); c = read()) {if (c == -1) return ;if (c == '-') iosig = true;   }for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;
}
//*/const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;*oh++ = c;
}template<class T>
inline void W(T x) {static int buf[30], cnt;if (x == 0) write_char('0');else {if (x < 0) write_char('-'), x = -x;for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;while (cnt) write_char(buf[cnt--]);}
}inline void flush() {fwrite(obuf, 1, oh - obuf, stdout);
}/*
template<class T>
inline void R(T &x) {static char c;static bool iosig;for (c = getchar(), iosig = false; !isdigit(c); c = getchar()) {if (c == -1) return ;if (c == '-') iosig = true; }for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;
}
// */const int MAXN = 200000 + 10;
const double PI = acos(-1.0);
const double eps = 1e-9;
const int INF = MAXN;double block;
int s, t, n, r, x, y;
int dis[MAXN], temp[MAXN];
bool vis[MAXN];struct point {double x, y;point() {}point(double x, double y) : x(x), y(y) {}inline double dis() {return sqrt(x * x + y * y);}inline double dis2() {return x * x + y * y;}
} p[MAXN];struct node {int to, w, rev;node() {}node(int to, int w, int rev) : to(to), w(w), rev(rev) {}
} ;std::vector<node> edge[MAXN];struct data {double num;int u, v, type;data() {}data(double num, int u, int v, int type): num(num), u(u), v(v), type(type) {}inline bool operator < (const data &a) const {return (num == a.num) ? (type > a.type) : (num < a.num);}
} q[MAXN << 1 | 1];inline void add_edge(int x, int y, int w) {edge[x].push_back(node(y, w, edge[y].size()));edge[y].push_back(node(x, 0, edge[x].size() - 1));
}inline bool bfs(int s, int t) {static std::queue<int> q;for (int i = s; i <= t; ++i) dis[i] = -1;for (int i = s; i <= t; ++i) temp[i] = 0;dis[s] = 0, q.push(s);while (!q.empty()) {int cur = q.front();q.pop();for (int p = 0; p < edge[cur].size(); ++p) {node *e = &edge[cur][p];if (e->w > 0 && dis[e->to] == -1) dis[e->to] = dis[cur] + 1, q.push(e->to);}}return dis[t] != -1;
}inline int dfs(int cur, int low, int t) {if (cur == t) return low;int delta = 0;for (int &p = temp[cur]; p < edge[cur].size(); ++p) {node *e = &edge[cur][p];if (dis[e->to] == dis[cur] + 1 && e->w > 0) {int ret = dfs(e->to, std::min(low - delta, e->w), t);e->w -= ret, edge[e->to][e->rev].w += ret;if ((delta += ret) == low) break ;}}return delta;
}int ret, ans;inline void pop_flow(int u, int v) {std::vector<node>::iterator it, it1;bool flag;for (it = edge[u].begin(); it != edge[u].end(); ++it) if (it->to == v) {flag = it->w, it = edge[u].erase(it);break ;} for (; it != edge[u].end(); ++it) edge[it->to][it->rev].rev--;for (it = edge[v].begin(); it != edge[v].end(); ++it)if (it->to == u) {it = edge[v].erase(it);break ;}for (; it != edge[v].end(); ++it) edge[it->to][it->rev].rev--;if (flag) return ;ans--;for (it = edge[s].begin(); it != edge[s].end(); ++it)if (it->to == u) {it->w ^= 1, edge[it->to][it->rev].w ^= 1;break ;}for (it = edge[t].begin(); it != edge[t].end(); ++it)if (it->to == v) {it->w ^= 1, edge[it->to][it->rev].w ^= 1;break ;}while (bfs(s, t))do ret = dfs(s, INF, t);while (ans += ret, ret);
}inline bool check(double x) {int cnt = 0;for (int i = s; i <= t; ++i) edge[i].clear();for (int i = 1; i <= n; ++i) {double dis = p[i].dis();if (dis > x + r || dis < r - x) return false;if (dis + r <= x) for (int j = 1; j <= n; ++j) add_edge(i, j + n, 1);else {double angle1 = atan2(p[i].y, p[i].x);double angle2 = acos(((double)r * r + dis * dis - x * x) / 2.0 / dis / r);double al = angle1 - angle2, ar = angle1 + angle2;while (al < 0) al += 2.0 * PI;while (ar < 0) ar += 2.0 * PI;int pl = al / block, pr = ar / block;q[++cnt] = data(al - block * pl, i, pl + 1 + n, 1), pl++;q[++cnt] = data(ar - block * pr, i, pr + 1 + n, 0), pr++;if (al <= ar) for (int j = pl + 1; j <= pr; ++j) add_edge(i, j + n, 1);else {for (int j = pl + 1; j <= n; ++j) add_edge(i, j + n, 1);for (int j = 1; j <= pr; ++j) add_edge(i, j + n, 1);}} }for (int i = 1; i <= n; ++i) add_edge(s, i, 1), add_edge(i + n, t, 1);std::sort(q + 1, q + cnt + 1), ret = ans = 0;while (bfs(s, t))do ret = dfs(s, INF, t);while (ans += ret, ret);if (ans == n) return true;for (int i = 1; i <= cnt; ++i) {if (q[i].type) {add_edge(q[i].u, q[i].v, 1);while (bfs(s, t))do ret = dfs(s, INF, t);while (ans += ret, ret);if (ans == n) return true;} else pop_flow(q[i].u, q[i].v);}return false;
}inline void solve() {R(n), R(r), block = PI * 2.00 / n, s = 0, t = 2 * n + 1;for (int i = 1; i <= n; ++i) R(x), R(y), p[i] = point(x, y);double l = -eps, r = 300;while (l + eps < r) {double mid = (l + r) / 2;(check(mid)) ? r = mid : l = mid;}printf("%0.8f", r);
}int main() {freopen("in.in", "r", stdin);solve();return 0;
}

NOI模拟(5.14) JSOID1T3 绝地反击 (bzoj5316)相关推荐

  1. 信息学奥赛一本通 1970:【15NOIP普及组】扫雷游戏 | OpenJudge NOI 1.8 14:扫雷游戏地雷数计算 | 洛谷 P2670 [NOIP2015 普及组] 扫雷游戏

    [题目链接] ybt 1970:[15NOIP普及组]扫雷游戏 OpenJudge NOI 1.8 14:扫雷游戏地雷数计算 洛谷 P2670 [NOIP2015 普及组] 扫雷游戏 [题目考点] 1 ...

  2. OpenJudge NOI 1.7 14:大小写字母互换

    [题目链接] OpenJudge NOI 1.7 14:大小写字母互换 [题目考点] 1. 字符串 2. 大小写转换 'a'的ASCII码是97,'A'的ASCII码是65,同一字母的大小写字母的AS ...

  3. 信息学奥赛一本通 1172:求10000以内n的阶乘 | OpenJudge NOI 1.6 14:求10000以内n的阶乘

    [题目链接] ybt 1172:求10000以内n的阶乘 OpenJudge NOI 1.6 14:求10000以内n的阶乘 [题目考点] 1. 高精度 考察:高精乘低精 高精度计算讲解 [解题思路] ...

  4. 信息学奥赛一本通 1118:铺地毯 | 1863:【11NOIP提高组】铺地毯 | OpenJudge NOI 1.9 14 | 洛谷 P1003 [NOIP2011 提高组] 铺地毯

    [题目链接] ybt 1118:铺地毯 ybt 1863:[11NOIP提高组]铺地毯 OpenJudge NOI 1.9 14:铺地毯 洛谷 P1003 [NOIP2011 提高组] 铺地毯 [题目 ...

  5. 信息学奥赛一本通 1070:人口增长 | OpenJudge NOI 1.5 14:人口增长问题

    [题目链接] ybt 1070:人口增长 OpenJudge NOI 1.5 14:人口增长问题 [题目考点] 1. 循环求幂 设变量r初始值为1:int r = 1; 循环n次每次循环中输入变量a, ...

  6. 信息学奥赛一本通 1052:计算邮资 | OpenJudge NOI 1.4 14

    [题目链接] ybt 1052:计算邮资 OpenJudge NOI 1.4 14:计算邮资 [题目考点] 1. if-else语句 [解题思路] 设邮件总重为w克,需要邮资r元 1000克以内收基本 ...

  7. 信息学奥赛一本通 1032:大象喝水 | OpenJudge NOI 1.3 14

    [题目链接] ybt 1032:大象喝水 OpenJudge NOI 1.3 14:大象喝水 [题目考点] 1. 数学知识 柱体体积 = 底面积*高 圆面积 = π∗r2\pi *r^2π∗r2 长度 ...

  8. [模拟] leetcode 14 最长公共前缀

    [模拟] leetcode 14 最长公共前缀 1.题目 题目链接 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例1: 输入: [& ...

  9. JZOJ 7066. 【2021.4.24 NOI模拟】ehzeux与圆周(DP)

    JZOJ 7066. [2021.4.24 NOI模拟]ehzeux与圆周 题目大意 圆周上有2∗n2*n2∗n个点,两两相连构成nnn个点对,其中有mmm个点对已经连好,求所有方案下的连通块数量和. ...

  10. Cisco PT模拟实验(14) 路由器OSPF动态路由的配置

    Cisco PT模拟实验(14) 路由器OSPF动态路由的配置 实验目的: 掌握OSPF动态路由选择协议的配置方法 掌握路由选择表中的OSPF路由描述 熟悉路由选择和分组转发的原理及过程 实验背景: ...

最新文章

  1. google gn构建系统的介绍
  2. 从五个方面做IT职业规划
  3. 命令行工具cobra的使用
  4. java中修改密码_java怎样修改用户名密码?
  5. 2019安卓机皇已定?三星Note10系列被曝将在8月10日发布
  6. python从入门到实践答案第六章-《Python从入门到实践》第六章动手试一试
  7. Android日期格式化
  8. exec 直接赋值_了解 JavaScript 解构赋值
  9. 新电脑磁盘可存储信息数百年
  10. 「大学生offer内推计划」:阿里/百度/华为等一线大厂都在抢这样的人!
  11. 【可视化编程一】关于Unity可视化编程(Visual Scripting)
  12. 2022级sdut知到/智慧树---c语言第一章测试题解
  13. 分支定界法求解整数规划
  14. IE兼容性视图无法添加网站
  15. Excel2007中文显示乱码的解决方法(亲自实践)
  16. python 时间格式处理
  17. gcc -O0 -O1 -O2 -O3 -Os 编译优化等级
  18. Python/Basemap绘制美国人口分布示意图
  19. 树莓派自定义游戏,Minecraft硬件编程,建造房屋,我的世界还可以这样玩
  20. 智芯传感微差压气体压力传感器成功入围第三届“SIA感知领航优秀项目征集”年度杰出产品及技术成长型企业组

热门文章

  1. 奥城大学计算机专业,美国研究生双录取的大学及可提供学位详情
  2. vs2019编译的程序在win7环境上运行失败
  3. 乒乓球:浅析业余高手从输球中总结的10条心得!
  4. 输入一个分数,将其约分为最简分式
  5. 想知道“照片识别文字”的技巧吗?快看这几个方法
  6. 数字电路基础:系统设计优化
  7. Python实现简易图形用户界面计算器
  8. 统计学_显著性检验综述
  9. word页码怎么从指定页开始设置?
  10. CPU工作方式、多核心、超线程技术详解[转贴]