2015-2016 Northwestern European Regional Contest (NWERC 2015) 补题
来源:互联网 发布:java程序员技能要求 编辑:程序博客网 时间:2024/05/30 12:30
C.Cleaning Pipes
题意:给出n条管道(线段),任意两个管道之间之多有一个交点,忽略一个管道头部和其他管道的交点,问能否选出一个不相交的管道集合来使得所有交点都被这些管道覆盖。
思路:将管道抽象成点,两个管道的交点抽象成边,那么问题转化成判断新建的图是否是一个二分图。
判断二分图最常用的方法就是染色法,本题当然也就可以用,然而我看dalao的代码还学了另一种方法:利用并查集判断,感觉这种方法的本质就是利用二分图不含奇环的性质(我自己yy的)。
具体做法就是将点集扩大两倍,i,j之间有边就merge(i, j + n),merge(i + n, j).最后判断一下i和i + n是否属于同一个集合。如果有一个属于同一个集合,则说明该图不是二分图。
代码:
#include<bits/stdc++.h>#define ll long longusing namespace std;const int MAXN = 2020;struct P{ int x, y; P(int _x = 0, int _y = 0) : x(_x), y(_y) {} bool operator == (P &b) { return x == b.x && y == b.y; }}well[MAXN], L[MAXN], R[MAXN];//计算向量p1p2与向量p1p3的叉积,若p1p3在p1p2的逆时针方向,则返回>0,顺时针方向返回<0int mul(P p1, P p2, P p3){ return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);}bool intersect(P p1,P p2,P q1,P q2){//快速排斥 if(max(p1.x,p2.x)<min(q1.x,q2.x)|| max(q1.x,q2.x)<min(p1.x,p2.x)|| max(p1.y,p2.y)<min(q1.y,q2.y)|| max(q1.y,q2.y)<min(p1.y,p2.y)) return 0;//跨立试验 if(1ll * mul(p1,p2,q1)*mul(p1,p2,q2) <= 0 && 1ll * mul(q1,q2,p1)*mul(q1,q2,p2) <= 0) return 1; return 0;}int f[MAXN];int getf(int k){ return k == f[k] ? k : f[k] = getf(f[k]);}void merge(int x, int y){ x = getf(x); y = getf(y); f[x] = y;}int main(){ int n, m, t; cin >> n >> m; for(int i = 1; i <= n; i++) scanf("%d %d", &well[i].x, &well[i].y); for(int i = 1; i <= m; i++) { scanf("%d %d %d", &t, &R[i].x, &R[i].y); L[i] = well[t]; f[i] = i; f[m + i] = m + i; } int x, y; for(int i = 1; i <= m; i++) for(int j = i + 1; j <= m; j++) { if(L[i] == L[j]) continue; if(intersect(L[i], R[i], L[j], R[j])) { merge(i, j + m); merge(i + m, j); } } for(int i = 1; i <= m; i++) if(getf(i) == getf(i + m)) { cout << "impossible"; return 0; } cout << "possible";}
D.Debugging
题意:要调试一个n行的代码,有两种方法:
1. 在任意行加printf语句,花费p时间
2. 运行代码,花费r时间
问在你采取最优策略的情况下,最坏情况需要花费多少时间。
思路:一上来就想到了那个扔鸡蛋的问题。。感觉特别相似。。
队友想了一个 n^2 的 dp转移,还用尽办法用线段树优化到n(logn)^2,然而还是t了,归根结底是因为用dp转移的话会有很多无用的状态被计算,想要避免这些无用计算,就要把for循环dp换成记忆化搜索。
基本转移方程:
设dp[n] 表示在最坏的情况下debug n行代码所需要的最少的时间.
dp[n] = min((i-1)*p+dp[ceil(n/i)])+r;
也就是枚举将n尽量等分成i段,bug出现在划分出的最长的段里,然后进行递归计算。
代码:
#include<bits/stdc++.h>#define ll long longusing namespace std;ll r, p, dp[1000010];ll ceil(ll n, ll m)// n / m 取上整数{ return (n + m - 1) / m;}ll dfs(ll n){ if(dp[n] != -1) return dp[n]; ll ans = 1e18; for(int i = 2; i <= n; i++) ans = min(ans, 1ll * (i - 1) * p + dfs(ceil(n, i)) + r); return dp[n] = ans;}int main(){ ll n; memset(dp, -1, sizeof(dp)); dp[0] = dp[1] = 0; cin >> n >> r >> p; cout << dfs(n);}这样求解已经很快了,但是大佬们还想出了更强的优化方法:点击打开链接
疯狂Orz
G.Guessing Camels
题意:给出三个序列,问这三个序列当中有多少对数是同样偏序的。
思路:逆向思维,用总数减去在三个序列中不是同样偏序的数对的数量。
现在就是考虑怎么求不满足的对数.
我们可以发现不满足偏序性质的这一对,一定是在某两个序列里偏序关系是相同的,那么我们可以对每两个序列求一次不满足题意的偏序对的个数.但是这样算的话,同一个数对会被计算两次,所以把最后的答案除以2就是最终的结果了.
我们可以发现不满足偏序性质的这一对,一定是在某两个序列里偏序关系是相同的,那么我们可以对每两个序列求一次不满足题意的偏序对的个数.但是这样算的话,同一个数对会被计算两次,所以把最后的答案除以2就是最终的结果了.
然后问题变成怎么求两个序列中不同偏序的数对个数。
将第一个数组看成标准序列,另一个数组看成一种标准序列的排列,那么问题就又转化成了类似求逆序对的个数,用树状数组搞搞就好了。
代码:
#include<bits/stdc++.h>#define ll long longusing namespace std;const int MAXN = 200020;int a[MAXN], b[MAXN], c[MAXN], pos[MAXN], bit[MAXN];int n;int sum(int i){ int res = 0; while(i) { res += bit[i]; i -= i & -i; } return res;}void add(int i, int delta){ while(i <= n) { bit[i] += delta; i += i & -i; }}ll solve(int *x, int *y){ memset(bit, 0, sizeof(bit)); for(int i = 1; i <= n; i++) pos[x[i]] = i; ll ans = 0; for(int i = n; i >= 1; i--) { ans += sum(pos[y[i]]); add(pos[y[i]], 1); } return ans;}int main(){ cin >> n; for(int i = 1; i <= n; i++) scanf("%d", a + i); for(int i = 1; i <= n; i++) scanf("%d", b + i); for(int i = 1; i <= n; i++) scanf("%d", c + i); ll ans = 1ll * (n - 1) * n / 2; ans -= (solve(a, b) + solve(b, c) + solve(c, a)) / 2; cout << ans << endl;}
阅读全文
0 0
- 2015-2016 Northwestern European Regional Contest (NWERC 2015) 补题
- 2015-2016 Northwestern European Regional Contest (NWERC 2015) E
- 2015-2016 Northwestern European Regional Contest (NWERC 2015)
- 2015-2016 Northwestern European Regional Contest (NWERC 2015) 7/11 待补
- 2015-2016 Northwestern European Regional Contest (NWERC 2015) E. Elementary Math
- C-Cleaning Pipes(判断两线段相交+二分图判定) 2015-2016 Northwestern European Regional Contest (NWERC 2015)
- 2014-2015 Northwestern European Regional Contest (NWERC 2014)【solved:7 / 11】
- 2015-2016 Northwestern European Regional Contest 训练总结 【5+2】【待补】
- 2013-2014 Northwestern European Regional Contest (NWERC 2013)
- 2015-2016 Northwestern European Regional Contest I.Identifying Map Tiles(超级技巧+脑洞)
- 2012-2013 Northwestern European Regional Contest (NWERC 2012)【solved:6 / 11】
- 2015-2016 ACM-ICPC Northeastern European Regional Contest (NEERC 15)
- 2014-2015 ACM-ICPC Northeastern European Regional Contest (NEERC 14)
- 2015-2016 ACM-ICPC Northeastern European Regional Contest (NEERC 15)题解
- ACM ICPC 2017 Warmup Contest 4(ACM Northeastern European Regional Contest,Northern Subregion 2015)
- 2006 ACM Northwestern European Programming Contest C题(二分求最大)
- 2014-2015 ACM-ICPC Northeastern European Regional Contest (NEERC 14) 解题报告
- ACM ICPC 2017 Warmup Contest 2(ACM Northeastern European Regional Contest,Northern Subregion 2016)
- bzoj3295 动态逆序对
- CMake 安装
- CodeForces
- 浅谈delegate为什么用weak修饰
- Selenium模拟操作中按钮点击(click)失效问题和文本框输入内容失败问题
- 2015-2016 Northwestern European Regional Contest (NWERC 2015) 补题
- 代码规则,自己总结
- C和指针考试——整理
- Vim光标定位操作快捷键
- 实验吧_隐写_小苹果
- 动态规划-最长公共子序列、最长公共子串
- 晨间日记 自用
- 集合collection 接口
- 用spring mvc框架的模拟实现来学习反射和注解