首页 > 代码库 > codeforces round #418 div 2
codeforces round #418 div 2
这场是吕队长的orz
A:如果k>1 那么肯定是可以的 因为两个数必然有大小关系 小的放在大的前面就行了 k=1 填进去判一下就行了
#include<bits/stdc++.h> using namespace std; const int N = 1010; int n, k, pos; int a[N], b[N]; int main() { scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); if(a[i] == 0) pos = i; } for(int i = 1; i <= k; ++i) scanf("%d", &b[i]); if(k > 1) { puts("Yes"); return 0; } a[pos] = b[1]; for(int i = 1; i <= n; ++i) { for(int j = i + 1; j <= n; ++j) if(a[i] >= a[j]) { puts("Yes"); return 0; } } puts("No"); return 0; }
B:这道题略坑wa了三发
两个序列肯定有一个位置不同 这是题目给出的条件 也就是说不用判两个序列相同的情况
题目要求构造出的排列和a b各有且仅有一个位置不同 那么这样说明a和b至多有两个位置不同 至少一个位置不同
如果一个位置不同 那么找出一个没选过且和ab该位均不同的数字填上
两个位置不同 对于这两个位置 肯定一个对应填上a 一个对应填上b 那么就是要看两种中哪种合法
先将一种情况带入。扫描判一下,不成立就换另一种情况。
#include<bits/stdc++.h> using namespace std; const int N = 1010; int n; int a[N], b[N], used[N], p[N], pos[N]; int main() { scanf("%d", &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) { p[i] = a[i]; if(a[i] != b[i]) pos[++pos[0]] = i; else used[a[i]] = 1; } if(pos[0] == 1) { for(int i = 1; i <= n; ++i) if(!used[i]) p[pos[1]] = i; for(int i = 1; i <= n; ++i) printf("%d ", p[i]); return 0; } p[pos[1]] = b[pos[1]]; p[pos[2]] = a[pos[2]]; memset(used, 0, sizeof(used)); for(int i = 1; i <= n; ++i) { if(used[p[i]]) { p[pos[1]] = a[pos[1]]; p[pos[2]] = b[pos[2]]; break; } used[p[i]] = 1; } for(int i = 1; i <= n; ++i) printf("%d ", p[i]); return 0; }
C:这道题忘记清空数组wa了4发罚时爆炸。。。1小时才做出来。。。
感觉很像一个dp,实际上也是一个dp。
dp[i][j][c]表示i位置至多刷了j次,这个位置刷后为c的最长序列
容易得出 如果这位不等于c dp[i][j][c]=dp[i-1][j-1][c]+1 否则等于dp[i-1][j][c]。用mx[j][c]记录刷了至多j次最长的序列的长度
那么询问就是O(1)的了。
mx[j][c]要用mx[j-1][c]更新 因为我的程序原先j是到i的,所以当j>1时dp[i][j][c]就是0,不能更新以后。
这样写也可以。。。
#include<bits/stdc++.h> using namespace std; const int N = 1510; int n, q, k; char s[N]; int dp[2][N][27], mx[N][27]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; ++i) { k ^= 1; memset(dp[k], 0, sizeof(dp[k])); for(int c = 0; c < 26; ++c) { for(int j = 0; j <= n; ++j) { if(c != s[i] - ‘a‘) { if(j) dp[k][j][c] = dp[k ^ 1][j - 1][c] + 1; } else dp[k][j][c] = dp[k ^ 1][j][c] + 1; mx[j][c] = max(mx[j][c], dp[k][j][c]); } } } scanf("%d", &q); while(q--) { int m; char s[10]; scanf("%d%s", &m, s); printf("%d\n", mx[m][s[0] - ‘a‘]); } return 0; }
D:比赛时以为是圆的异或面积并,于是就gg了。。。
我们可以这样讨论:对于一个圆,当他被覆盖的次数是0或者%2=1时才加上他的面积。
为什么呢?我们不妨这么想:对于一些圆,他们互相包含,也就是说他们是一堆圆套着一堆圆。
那么这里运用贪心的思想:第一个圆最大,我们要加上,放到第一组,第二个圆第二大,我们也要加上,放到第二组。但是到第三个圆,无论放哪里,都得减去,于是我们放到第一组。
第四个圆,放到第一组的话,就可以加上,于是放到第一组,以此类推。于是我们就按着这个思路贪心,记录每个圆呗覆盖次数,然后计算面积就行了。
#include<bits/stdc++.h> using namespace std; const int N = 1010; const double pi = 3.1415926535898; struct data { double x, y, r; } x[N]; int n; double tot; double sqr(double x) { return x * x; } double dis(double x1, double x2, double y1, double y2) { return sqrt(sqr(x1 - x2) + sqr(y1 - y2)); } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%lf%lf%lf", &x[i].x, &x[i].y, &x[i].r); for(int i = 1; i <= n; ++i) { int cnt = 0; for(int j = 1; j <= n; ++j) if(j != i) if(dis(x[i].x , x[j].x, x[i].y, x[j].y) <= x[j].r - x[i].r) ++cnt; if(cnt == 0 || cnt % 2 == 1) tot += x[i].r * x[i].r * pi; else tot -= x[i].r * x[i].r * pi; } printf("%.10f\n", tot); return 0; }
codeforces round #418 div 2