2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16)【solved:9 / 11】
来源:互联网 发布:双核单片机 编辑:程序博客网 时间:2024/06/05 08:19
差两个题。F题好像是树状数组什么的。不太会。百度能搜到题解。感觉没看懂他在说啥。K题vj上好像有代码。
-update 2017年10月7日15:54:16
A - The game of Osho(SG函数)
题意:
有m堆石子,每堆有对应一个(Bi,Ni),表示这堆有Ni个石子,每次可以拿Bi^x个石子(1<=Bi^x<=Ni),谁不能拿谁输,1和2轮流拿,两人足够机智,问谁必胜。
思路:
请看Gym 101147A - The game of Osho(SG函数+二项展开)。
B - Street(最短路)
题意:
有一些矩形的阴影块,问你从一个大矩形地图的底边跑到顶边,要走过的非阴影路程最短是多少。
数据:
不超过100个阴影块,矩形边长不超过1e9。
思路:
这题其实很简单,因为它题目说了,既没有矩形相交的情况。块数也只有100,那么是不是只要预处理出俩俩矩形块之间距离,然后跑一个最短路就好了。
预处理距离的时候,一定要小心,有些逻辑判断先后顺序倒一下,就T啊WA啊的,原因你萌显然自己也清楚。
#include <bits/stdc++.h>using namespace std;const int maxn = 100 + 5;const double INF = 1e14;typedef long long LL;int n, H, W;struct Rec{ int h, w, dis, tag; bool operator < (const Rec &other)const { if(dis != other.dis) return dis < other.dis; return tag < other.tag; }}rec[maxn];double G[maxn][maxn];double calc(double x, double y){ return sqrt(x * x + y * y);}double dist(int x, int y){ if(x == 0) return rec[y].dis; LL xup = (LL)rec[x].dis + rec[x].h; LL ydown = rec[y].dis; if(rec[x].tag == rec[y].tag) { return ydown - xup; } else { if(xup >= ydown) return W - rec[x].w - rec[y].w; if(rec[x].w + rec[y].w >= W) return ydown - xup; else return calc(W - rec[x].w - rec[y].w, ydown - xup); }}double d[maxn];bool inque[maxn];double spfa(int sg, int Vs){ for(int i = 1; i <= Vs; i++) d[i] = INF; memset(inque, 0, sizeof(inque)); queue<int>que; d[sg] = 0; que.push(sg); inque[sg] = true; while(que.size()) { int cur = que.front();que.pop(); inque[cur] = false; for(int i = 0; i <= Vs; i++) { if(i == cur) continue; if(d[cur] + G[cur][i] < d[i]) { d[i] = d[cur] + G[cur][i]; if(!inque[i]) { inque[i] = true; que.push(i); } } } }}int main(){ freopen("street.in", "r", stdin); int T; scanf("%d", &T); while(T--) { scanf("%d%d%d", &n, &H, &W); for(int i = 1; i <= n; i++) { int h, w, dis, tag; scanf("%d%d%d%d", &h, &w, &dis, &tag); rec[i] = {h, w, dis, tag}; } sort(rec + 1, rec + n + 1); //init map for(int i = 0; i <= n; i++) { for(int j = 0; j <= n; j++) { if(i == j) G[i][j] = 0; else G[i][j] = INF; } } for(int i = 0; i <= n; i++) { for(int j = i + 1; j <= n; j++) { G[i][j] = G[j][i] = dist(i, j); } } spfa(0, n); double ans = H; for(int i = 1; i <= n; i++) { double temp = H - rec[i].dis - rec[i].h + d[i]; if(temp < ans) ans = temp; } printf("%.6f\n", ans); } return 0;}
C - The Wall(最小顶点覆盖)
题意:
一个n*m的区域,有n+m个防御工事,x=i(0<=i<=n-1)可以杀死i<=x < i+1里的所有敌人,以(n/2,y)(0<=y<=m-1)为圆心,n/2为半径的上半圆弧会对杀死前面距该圆弧距离不超过1的敌人(注意不能跨圆弧杀人),现在给出p个敌人的坐标,问至少需要开放多少防御工事可以消灭多少敌人。
思路:
最小顶点覆盖几乎裸题。
#include <bits/stdc++.h>using namespace std;const int maxn = 10000 + 5;const double eps = 1e-7;int n, m, p;int used[200 + 5], match[200 + 5];vector<int> G[200 + 5];bool dfs(int v){ used[v] = 1; for(int i = 0; i < G[v].size(); i++) { int u = G[v][i], w = match[u]; if(w < 0 || !used[w] && dfs(w)) { match[v] = u; match[u] = v; return true; } } return false;}int hungary(int V){ int res = 0; memset(match, -1, sizeof(match)); for(int u = 0; u < V; u++) { if(match[u] < 0) { memset(used, 0, sizeof(used)); if(dfs(u)) res++; } } return res;}struct node{ double x, y;}nodes[maxn];int sign(double x){ if(fabs(x) < eps) return 0; if(x > eps) return 1; return -1;}double dist(double x1, double y1, double x2, double y2){ return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));}bool check(int a, int b){ double r = 1.0 * n / 2; double ox = r, oy = b; if(sign(nodes[a].y - oy) <= 0) return false; double temp = dist(ox, oy, nodes[a].x, nodes[a].y); if(sign(temp - r) != -1 && sign(temp - 2 * r) == -1) return true; return false;}int main(){ freopen("wall.in","r",stdin); int T; scanf("%d", &T); while(T--) { scanf("%d%d%d", &n, &m, &p); for(int i = 0; i < n + m; i++) G[i].clear(); for(int i = 0; i < p; i++) { double x, y; scanf("%lf%lf", &x, &y); nodes[i] = {x, y}; } for(int i = 0; i < p; i++) { int fx = nodes[i].x; for(int j = m - 1; j >= 0; j--) { if(check(i, j)) { G[fx].push_back(n + j); break; } } } for(int i = 0; i < n; i++) { sort(G[i].begin(), G[i].end()); G[i].resize(unique(G[i].begin(), G[i].end()) - G[i].begin()); } printf("%d\n", hungary(n)); } return 0;}
D - Popcorn(组合数)
题意:
n个不同的物品选m件,求方案数
思路:
组合数裸题
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 20 + 5;LL C[maxn][maxn];int main(){ freopen("popcorn.in", "r", stdin); for(int i = 0; i < maxn; i++) C[i][0] = 1; for(int i = 1; i < maxn; i++) { for(int j = 1; j <= i; j++)//!!! { C[i][j] = C[i - 1][j] + C[i - 1][j - 1]; } } int T, n, m; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); printf("%lld\n", C[n][m]); } return 0;}
E - Jumping(bfs)
题意:
n个点,每个点有一个跳跃的距离d[i],i只能跳到i-d[i]和i+d[i]且不能跳出去,问每个顶点到n的跳的最少的次数。
思路:
直接建图跑一个宽搜就行了,建图的时候反向建图,就只要跑一遍就够了。很常用的技巧。
#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 5;const int INF = 0x3f3f3f3f;vector<int>G[maxn];int vis[maxn], d[maxn];void bfs(int n){ queue<int>que; que.push(n); d[n] = 0; while(que.size()) { int cur = que.front();que.pop(); if(vis[cur]) continue; vis[cur] = 1; for(auto to : G[cur]) { if(d[to] > d[cur] + 1) { d[to] = d[cur] + 1; que.push(to); } } }}int main(){ freopen("jumping.in", "r", stdin); int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); //init for(int i = 1; i <= n; i++) G[i].clear(); memset(vis, 0, sizeof(vis)); memset(d, INF, sizeof(d)); for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); if(i - x >= 1) G[i - x].push_back(i); if(i + x <= n) G[i + x].push_back(i); } bfs(n); for(int i = 1; i <= n; i++) { printf("%d\n", d[i] == INF ? -1 : d[i]); } } return 0;}
G - The Galactic Olympics(第二类斯特林数)
题意:
n场不同的比赛,派k个人去,一个人可以参加多场比赛且至少参加一场,每场比赛只能且必须要有一个人参加,问方案数。
思路:
第二类斯特林数。然后就好做了。
#include <bits/stdc++.h>using namespace std;const int maxn = 1e3 + 5;const int mod = 1e9 + 7;typedef long long LL;LL fac[maxn];LL dp[maxn][maxn];int main(){ freopen("galactic.in", "r", stdin); for(int i = 0; i <= 1000; i++) dp[i][i] = 1; for(int i = 2; i <= 1000; i++) { for(int j = 1; j < i; j++) { dp[i][j] = 1LL * j * dp[i - 1][j] % mod + dp[i - 1][j - 1]; dp[i][j] %= mod; } } fac[0] = 1; for(int i = 1; i <= 1000; i++) fac[i] = fac[i - 1] * i % mod; int T; scanf("%d", &T); while(T--) { int games, people; scanf("%d%d", &games, &people); if(games < people) puts("0"); else printf("%lld\n", dp[games][people] * fac[people] % mod); } return 0;}
H - Commandos(dp)
题意:
一栋楼有十层,(f,x,y)表示f层的x-y房间,每次可以用(f,x,y)移动到(f-1,x,y)或(f,x+1,y)或(f,x,y+1),初始在(10,1,1),现在给出一些房间中的人数,问最多可以带走多少人。
思路:
。。水dp。
#include <bits/stdc++.h>using namespace std;int ma[15][15][15];int dp[15][15][15];int main(){ freopen("commandos.in", "r", stdin); int T; scanf("%d", &T); while(T--) { memset(ma, 0, sizeof(ma)); int n; scanf("%d", &n); while(n--) { int f, x, y, h; scanf("%d%d%d%d", &f, &x, &y, &h); ma[f][y][x] = h; } for(int i = 10; i >= 1; i--) { for(int j = 1; j <= 10; j++) { for(int k = 1; k <= 10; k++) { int choose = 0; choose = max(dp[i + 1][j][k], max(dp[i][j - 1][k], dp[i][j][k - 1])); dp[i][j][k] = choose + ma[i][j][k]; } } } int ans = 0; for(int i = 1; i <= 10; i++) { for(int j = 1; j <= 10; j++) { ans = max(ans, dp[1][i][j]); } } printf("%d\n", ans); } return 0;}
I - On the way to the park(扫描线)
题意:
给出一些小圆的圆心和半径,问一个圆心在x轴上,半径为R的大圆可以包含多少小圆的和最大为多少。
思路:
可以把小圆,降到x轴上,(小圆和x轴的交点),然后类似扫描线的思路记录一下最大是多少就行了。
#include <bits/stdc++.h>using namespace std;const int maxn = 1e5+ 5;typedef long long LL;typedef pair<double, int>pdi;pdi a[2 * maxn];int main(){ freopen("walk.in", "r", stdin); int T; scanf("%d", &T); while(T--) { int n, R; scanf("%d%d", &n, &R); int cnt = 0; for(int i = 0; i < n; i++) { int x, y, r; scanf("%d%d%d", &x, &y, &r); if(r > R || abs(y) > R - r) continue; double delta = sqrt(1.0 * (R - r) * (R - r) - 1.0 * y * y); a[cnt++] = {-delta + 1.0 * x, r}; a[cnt++] = {delta + 1.0 * x, -r}; } sort(a, a + cnt, [](pdi x, pdi y) { if(x.first != y.first) return x.first < y.first; return x.second > y.second; }); LL ans = 0, sum = 0; for(int i = 0; i < cnt; i++) { sum += a[i].second; ans = max(ans, sum); } printf("%lld\n", ans); } return 0;}
J - Whistle's New Car(dfs)
题意:
给出一棵有向树,有点权和边权,定义一个节点i的魅力值,为以节点i为根的子树中有多少个节点j,节点j的点权不小于j->i的简单路径上边权和,求所有点的魅力值。
数据:
n个节点,1<=n<=5e5,每个节点的点劝和每条边的边权范围都是1e9。
思路:
我们处理一下,每一条链的情况,我们记录从根结点到结点cur的路径长度为depth[cur],那么,我们是不是可以知道这条路径上,cur结点贡献的魅力值,应该是从cur结点的父结点开始往上一直到这条链的第pos个结点,都+1,这个pos可以通过二分得到。然后是一个区间更新,区间更新用树dp的方式传递,pos的父结点更新一个-1,是要抵消掉传上来月以后下面cur的+1的更新,从而达到从pos结点到cur结点的父结点的+1的区间更新操作。
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 500000 + 5;struct node{ int to, w;};vector<node>G[maxn];int val[maxn], path[maxn], fa[maxn];LL depth[maxn], ans[maxn];void dfs(int cur, int pa, int num){ for(auto o : G[cur]) if(o.to != pa) { fa[o.to] = cur; path[num] = o.to; depth[num] = depth[num - 1] + o.w; int pos = lower_bound(depth, depth + num+ 1, depth[num] - val[o.to]) - depth; if(pos < num) ans[cur]++, ans[fa[path[pos]]]--; dfs(o.to, cur, num + 1); ans[cur] += ans[o.to]; }}int main(){ freopen("car.in", "r", stdin); int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); //init for(int i = 1; i <= n; i++) G[i].clear(); memset(ans, 0, sizeof(ans)); for(int i = 1; i <= n; i++) { scanf("%d", &val[i]); } for(int i = 0; i < n - 1; i ++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); G[u].push_back({v, w}); G[v].push_back({u, w}); } path[0] = 1, depth[0] = 0; dfs(1, -1, 1); for(int i = 1; i <= n; i++) { printf("%lld%c", ans[i], i == n ? '\n' : ' '); } } return 0;}
- 2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16)【solved:9 / 11】
- CodeFroces GYM 2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16) B.street(最短路)
- 【bfs && 反向建边】2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16) Jumping
- ACM ICPC 2017 Warmup Contest 1(Nordic Collegiate Programming Contest 2016)
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) 【solved:9 / 12】
- 2016-2017 ACM-ICPC, NEERC, Central Subregional Contest【solved : 10 / 11】
- 2017 ACM Amman Collegiate Programming Contest
- 2017 ACM Amman Collegiate Programming Contest J
- GYM 2017 ACM Amman Collegiate Programming Contest
- 【Codeforces】2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) E 线段树+离散化
- 【Codeforces】2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) A Adjoin the Netwo
- 2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) Adjoin the Networks (树的直径)
- 2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) Disastrous Downtime(前缀和)
- 2015-2016 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2015) Goblin Garden Guards (数论)
- 2017-2018 ACM-ICPC, NEERC Problem G Galactic Collegiate Programming Contest(树状数组)
- 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017) 部分题/平衡树/最小环/思路bfs
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)【solved:12 / 13】
- 2016-2017 ACM-ICPC (SEERC 2016) 【solved:7 / 11】
- 2017算法课.08(Assign Cookies )
- 阿里云linux centos 一键部署web环境--图文详解
- 欢迎使用CSDN-markdown编辑器
- 动态规划练习一 02:最大子矩阵
- java学习之路之接口(3)--工厂设计模式
- 2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16)【solved:9 / 11】
- JDBC学习入门
- Android JNI局部引用表溢出
- 【错误】Oracle安装数据库教程及报错
- 数据结构 二叉搜索树
- Python 中append和extend 方法的区别
- 题目1066:字符串排序
- nginx实现tomcat的负载均衡
- Spring3.2和jdk1.8之间的兼容性错误