Codeforces Round #404 (Div. 2)——ABCDE
題目這裏
A.map裸題
#include <bits/stdc++.h> using namespace std; map <string, int> p; string s[] = { "Tetrahedron", "Cube", "Octahedron" , "Dodecahedron", "Icosahedron" }; int ss[] = {4, 6, 8, 12, 20}; int main() { ios::sync_with_stdio(false); for(int i = 0;i < 5View Code;i ++) p[s[i]] = ss[i]; int n, m = 0; string str; cin >> n; while(n --) cin >> str, m += p[str]; cout << m; return 0; }
B.貪心,先上的課盡早下課,後上的課盡量晚點上課
#include <bits/stdc++.h> using namespace std; int n, l, r, l1, l2, r1, r2, ans; int main() { ios::sync_with_stdio(View Codefalse); r1 = r2 = 1e9; cin >> n; while(n --) { cin >> l >> r; l1 = max(l1, l); r1 = min(r1, r); } cin >> n; while(n --) { cin >> l >> r; l2 = max(l2, l); r2 = min(r2, r); } ans = max(max(0, l2 - r1), max(0, l1 - r2)); cout << ans; return 0; }
C.先討論一下
如果n <= m ,那麽前 n - 1 天都是當天補滿,然後第 n 天被吃光
當 n > m , 前 m 天肯定吃不完的
然後第 m + 1 天鳥走之後(沒吃完)下一天再補上,就只有 n - 1 了
第 m + 2 天鳥走之後(沒吃完)再補上,就只有 n - 1 - 2 了
......
第 ans 天鳥走之後倉庫已經被吃光了
那麽就有 n - (ans - m) * (ans - m - 1) / 2 - ans <= 0
令 t = ans - m , 化簡以後就有 t * t + t >= 2 * (n - m)
這時候可以選擇二分,右邊界肯定是sqrt(2 * 1e18)啦,再大會爆long long
當然可以直接開根,然後左右小小調整一下就能出來結果
#include <bits/stdc++.h> using namespace std; int main() { unsigned long long n, m, ans; cin >> n >> m; if(n <= m) cout << n; else { n = (n - m) * 2, ans = sqrt(n); while(ans * ans + ans >= n) ans --;ans ++; while(ans * ans + ans < n) ans ++; cout << ans + m; } return 0; }View Code
D.為了避免重復,我們選擇這樣一個策略:
每當遇到一個左括號,我們計算包含這個左括號的合法序列數量加入ans
顯然如果當前左括號左邊有 L 個左括號(不含這個)
右邊有 R 個右括號,那麽對ans貢獻為
sigma(C(L,i ) * C(R,i + 1) ),0 <= i < R
然後我們用一個範德蒙恒等式就變成了求 C(L + R ,R - 1)
剩下求組合數就O(nlogn)預處理,O(1)計算即可
#include <cstdio> #include <iostream> const int Mod = 1e9 + 7; char s[200010]; long long ans, fac[200010], v[200010]; int calc(long long x, int k = Mod - 2) { long long ret = 1; for(;k;k >>= 1, x = x * x % Mod) if(k & 1) ret = ret * x % Mod; return ret; } long long C(int n, int m) { return fac[n] * v[m] % Mod * v[n - m] % Mod; } int main() { fac[0] = v[0] = 1; for(int i = 1;i <= 200000;i ++) fac[i] = fac[i - 1] * i % Mod, v[i] = calc(fac[i]); int l = 0, r = 0; scanf("%s", s); for(int i = 0;s[i];i ++) r += (s[i] == ‘)‘); for(int i = 0;s[i];i ++) { if(s[i] == ‘)‘) r --; else ans += C(l + r, r - 1), ans %= Mod, l ++; } printf("%lld", ans); return 0; }View Code
E.原序列為 1 - n 的排列,每次操作交換兩數位置,並操作後求出逆序對個數
轉化為二維模型就能很熟悉的聯系到cdq上,於是 cdq + 樹狀數組 解決即可
當然樹套樹也可做,不再分析思路
用cdq來做呢,我們每次計算這次操作對逆序對數的改變量即為
( l, a[r] )左上和右下矩陣中點的個數 + ( r, a[l] ) 左上和右下矩陣中點的個數
- ( l, a[l] ) 左上和右下矩陣中點的個數 - ( r, a[r] ) 左上和右下矩陣中點的個數
當然我們需要註意避免逆序對的重復計算
另外需要註意我們計算的是改變量,所以答案是需要累加的
#include <bits/stdc++.h> #define lb(x) (x & (-x)) #define rep(i, j, k) for(int i = j;i <= k;i ++) using namespace std; const int maxn = 200010, maxm = maxn * 5; struct node { int x, y, op, bel, id; bool operator < (const node &a) const { if(x != a.x) return x < a.x; if(y != a.y) return y < a.y; return id < a.id; } }q[maxm], q0[maxm]; int n, m, k, a[maxn], c[maxn]; long long ans[maxn]; void add(int i, int x) { while(i <= n) c[i] += x, i += lb(i); } int ask(int i) { int ret = 0; while(i > 0) ret += c[i], i -= lb(i); return ret; } void solve(int l, int r) { if(l == r) return; int mid = (l + r) >> 1, cnt = 0; solve(l, mid), solve(mid + 1, r); rep(i, l, mid) if(q[i].op == 3 || q[i].op == -3) q0[++ cnt] = q[i]; rep(i, 1 + mid, r) if(q[i].op != 3 && q[i].op != -3) q0[++ cnt] = q[i]; sort(q0 + 1, q0 + cnt + 1); rep(i, 1, cnt) { if(q0[i].op == 3 || q0[i].op == -3) add(q0[i].y, q0[i].op / 3); else ans[q0[i].bel] += ask(q0[i].y) * q0[i].op; } rep(i, 1, cnt) if(q0[i].op == 3 || q0[i].op == -3) add(q0[i].y, q0[i].op / -3); } int main() { ios::sync_with_stdio(false); int l, r; cin >> n >> m; rep(i, 1, n) a[i] = i, q[++ k] = (node){i, i, 3, 0, k}; rep(i, 1, m) { cin >> l >> r; if(l != r) { q[++ k] = (node){l - 1, n, -1, i, k}; q[++ k] = (node){n, a[l] - 1, -1, i, k}; q[++ k] = (node){l - 1, a[l] - 1, 2, i, k}; q[++ k] = (node){l, a[l], -3, 0, k}; q[++ k] = (node){r - 1, n, -1, i, k}; q[++ k] = (node){n, a[r] - 1, -1, i, k}; q[++ k] = (node){r - 1, a[r] - 1, 2, i, k}; q[++ k] = (node){r, a[r], -3, 0, k}; q[++ k] = (node){l - 1, n, 1, i, k}; q[++ k] = (node){n, a[r] - 1, 1, i, k}; q[++ k] = (node){l - 1, a[r] - 1, -2, i, k}; q[++ k] = (node){l, a[r], 3, 0, k}; q[++ k] = (node){r - 1, n, 1, i, k}; q[++ k] = (node){n, a[l] - 1, 1, i, k}; q[++ k] = (node){r - 1, a[l] - 1, -2, i, k}; q[++ k] = (node){r, a[l], 3, 0, k}; swap(a[l], a[r]); } } solve(1, k); rep(i, 1, m) { ans[i] += ans[i - 1]; cout << ans[i] << endl; } return 0; }View Code
代碼寫的很醜很暴力,僅供參考
Codeforces Round #404 (Div. 2)——ABCDE