今天唯一的成果就是把上次几个人一起开房打的那场cf补一下。
A. Combination Lock
此等水题看一眼样例加上那个配图我就明白题意了,可是手抽没有注释掉freopen,WA了一发。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1000 + 10; 5 6 char s1[maxn], s2[maxn]; 7 8 int main() 9 { 10 int n; cin >> n; 11 scanf("%s", s1); 12 scanf("%s", s2); 13 int ans = 0; 14 for(int i = 0; i < n; i++) 15 { 16 int a = s1[i] - '0'; 17 int b = s2[i] - '0'; 18 if(a < b) swap(a, b); 19 ans += min(a - b, 10 - a + b); 20 } 21 cout << ans << "\n"; 22 23 return 0; 24 }
B. School Marks
这道题本身不难,因为所给的n是奇数。但有可能会想错细节或漏掉情况。
n个数排好序,中间那个数一定是中位数,而且左右两边各n / 2个数。
所以我们看已知的k个数中比y小的数有多少个,如果大于n/2个,那么中位数一定小于y,无解。
如果k个数中不小于y的大于n / 2个,那么根据贪心,中位数已经在这些数里面了,所以剩下的n-k个数补成1就好了。
其次可以把中位数y插到这里面去,而且能算出中位数左边要补多少个1,右边要补多少个y。
注意在上面所有的情况中还要判断总数是否不超过x。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1000 + 10; 5 int a[maxn]; 6 7 int main() 8 { 9 //freopen("in.txt", "r", stdin); 10 11 int n, k, p, x, y; 12 cin >> n >> k >> p >> x >> y; 13 for(int i = 0; i < k; i++) scanf("%d", &a[i]); 14 sort(a, a + k); 15 int t = lower_bound(a, a + k, y) - a; 16 if(t > n / 2) { puts("-1"); return 0; } 17 18 int s = 0; 19 for(int i = 0; i < k; i++) s += a[i]; 20 if(k - t > n / 2) 21 { 22 int p = n - k; 23 if(s + p > x) { puts("-1"); return 0; } 24 printf("1"); 25 for(int i = 1; i < p; i++) printf(" 1"); 26 puts(""); return 0; 27 } 28 29 int l = n / 2 - t; 30 int r = n / 2 - k + t; 31 if(s + l + (r + 1) * y > x) { puts("-1"); return 0; } 32 bool print = false; 33 for(int i = 0; i < l; i++) { if(print) printf(" "); print = true; printf("1"); } 34 for(int i = 0; i <= r; i++) { if(print) printf(" "); print = true; printf("%d", y); } 35 36 return 0; 37 }
C. Ice Cave (BFS)
总体来说这场CF难度偏易,虽然比赛的时候逗比地爆一了。但是下来的时候,手写一遍,没有编译错误交上去还过了,比赛要是这状态,啧啧
这道题一开始没有理解题意,其实就是地图上的'.'走过一遍就变成'X',而且'X'就不能再走了,终点除外。
问从能否起点走到终点,而且把终点变成'X'
把题意理解了,直接BFS就好啦,而且vis标记都不用,直接修改地图就好了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 500 + 10; 5 6 char s[maxn][maxn]; 7 int n, m; 8 9 struct Node 10 { 11 int x, y; 12 Node(int x = 0, int y = 0):x(x), y(y) {} 13 }st, ed; 14 15 int dx[] = { 1, 0, -1, 0 }; 16 int dy[] = { 0, 1, 0, -1 }; 17 18 inline bool in(int x, int y) { return x > 0 && x <= n && y > 0 && y <= m; } 19 20 bool BFS() 21 { 22 queue<Node> Q; 23 Q.push(st); 24 while(!Q.empty()) 25 { 26 Node now = Q.front(); Q.pop(); 27 for(int i = 0; i < 4; i++) 28 { 29 int x = now.x + dx[i]; 30 int y = now.y + dy[i]; 31 if(!in(x, y)) continue; 32 if(s[x][y] == 'X') { if(x == ed.x && y == ed.y) return true; continue; } 33 s[x][y] = 'X'; 34 Q.push(Node(x, y)); 35 } 36 } 37 return false; 38 } 39 40 int main() 41 { 42 //freopen("in.txt", "r", stdin); 43 44 cin >> n >> m; 45 for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1); 46 scanf("%d%d%d%d", &st.x, &st.y, &ed.x, &ed.y); 47 printf("%s\n", BFS() ? "YES" : "NO"); 48 49 return 0; 50 }
D. Bad Luck Island (概率 DP)
题解写得很清楚,递推或者DFS都行。
1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 5 const int maxn = 100 + 5; 6 double d[maxn][maxn][maxn]; 7 8 int main() 9 { 10 int a, b, c; 11 cin >> a >> b >> c; 12 d[a][b][c] = 1.0; 13 for(int i = a; i >= 0; i--) 14 for(int j = b; j >= 0; j--) 15 for(int k = c; k >= 0; k--) 16 { 17 if(!i && !j) continue; 18 if(!i && !k) continue; 19 if(!j && !k) continue; 20 double cur = d[i][j][k]; 21 double tot = i*j + i*k + j*k; 22 if(i) d[i-1][j][k] += cur * (double)(i*k) / tot; 23 if(j) d[i][j-1][k] += cur * (double)(i*j) / tot; 24 if(k) d[i][j][k-1] += cur * (double)(j*k) / tot; 25 } 26 27 double aa = 0, bb = 0, cc = 0; 28 for(int i = 1; i <= a; i++) aa += d[i][0][0]; 29 for(int i = 1; i <= b; i++) bb += d[0][i][0]; 30 for(int i = 1; i <= c; i++) cc += d[0][0][i]; 31 32 printf("%.12f %.12f %.12f\n", aa, bb, cc); 33 34 return 0; 35 }
E. Infinite Inversions (树状数组 离散化)
可以把所求分成两个部分来计:
把这2n个数进行一次离散化,比如排序去重以后变成m个数。
那么经过m次操作,这m个数相较于初始状态是一个这m个数的排列。所以可以用树状数组计算一个这m个数之间的逆序数,注意这里不涉及位置没有变化的那些数。
这样我们便完成了第一部分的计数。
剩下的一部分是这m个数与其他位置未发生变化的逆序数。
预处理一下m个数中第i个数与第1个数之间有多少个数未发生位置改动sum[i]。
比如这m个数经过n次两两交换以后,第i个数的大小为rank[i],那么未发生位置改动的数与第i个数构成的逆序对有abs(sum[i] - sum[rank[i]])
举个栗子:
比如2 7互换,序列由
1 2 3 4 5 6 7 8 变成 1 7 3 4 5 6 2 8
2和7之间有4个数没有变(即3 4 5 6),对于2 7而言,7到2前面去了这是一个逆序对,也就是我们计数的第一部分。
对于2来说,2在7的位置,而且3 4 5 6都与2构成一个逆序对,因此贡献了4个逆序对;
对于7同样,7在2的位置,3 4 5 6在7的后面也贡献了4个逆序对。
所以最终答案为9
1 #include <cstdio> 2 #include <iostream> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 typedef long long LL; 8 const int maxn = 200000 + 10; 9 10 int a[maxn], b[maxn], x[maxn], r[maxn]; 11 LL sum[maxn], s[maxn]; 12 int n, m; 13 14 inline int lowbit(int x) { return x&(-x); } 15 16 void add(int x, LL d) 17 { while(x <= m) { s[x] += d; x += lowbit(x); } } 18 19 LL query(int x) 20 { 21 LL ans = 0; 22 while(x) { ans += s[x]; x -= lowbit(x); } 23 return ans; 24 } 25 26 int main() 27 { 28 //freopen("in.txt", "r", stdin); 29 30 cin >> n; 31 for(int i = 1; i <= n; i++) 32 { 33 scanf("%d%d", &a[i], &b[i]); 34 x[i*2-1] = a[i]; x[i*2] = b[i]; 35 } 36 sort(x + 1, x + 1 + n*2); 37 m = unique(x + 1, x + 1 + n*2) - x - 1; 38 for(int i = 1; i <= m; i++) 39 { 40 sum[i] = sum[i - 1] + x[i] - x[i - 1] - 1; 41 r[i] = i; 42 } 43 for(int i = 1; i <= n; i++) 44 { 45 int ta = lower_bound(x + 1, x + 1 + m, a[i]) - x; 46 int tb = lower_bound(x + 1, x + 1 + m, b[i]) - x; 47 swap(r[ta], r[tb]); 48 } 49 50 LL inv = 0; 51 for(int i = m; i > 0; i--) 52 { 53 inv += query(r[i]); 54 add(r[i], 1); 55 inv += abs(sum[i] - sum[r[i]]); 56 } 57 58 cout << inv << endl; 59 60 return 0; 61 }