Educational Codeforces Round 55 (Rated for Div. 2) Solution
A. Vasya and Book
Solved.
三種方式取$Min$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define INF 0x3f3f3f3f3f3f3f3f 6 int t; 7 ll n, x, y, d; 8 9 ll calc(ll x) 10 { 11 return x % d == 0 ? x / d : x / d + 1; 12 } 13 14 int main() 15 { 16 scanf("View Code%d", &t); 17 while (t--) 18 { 19 scanf("%lld%lld%lld%lld", &n, &x, &y, &d); 20 ll res = INF; 21 if ((abs(y - x)) % d == 0) res = min(res, (abs(y - x) / d)); 22 if ((y - 1) % d == 0) res = min(res, calc(x) + (y - 1) / d); 23 if ((n - y) % d == 0) res = min(res, calc(n - x) + (n - y) / d); 24 if (res == INF) res = -1; 25 printf("%lld\n", res); 26 } 27 return 0; 28 }
B. Vova and Trophies
Solved.
合併相同種類,再判斷是否有單獨的S使得替換掉它合併後得到更優解
1 #include <bits/stdc++.h> 2 using namespace std;View Code3 4 #define N 100010 5 #define pii pair <int, int> 6 int n, m; 7 char s[N]; 8 pii a[N]; 9 10 int main() 11 { 12 while (scanf("%d", &n) != EOF) 13 { 14 scanf("%s", s + 1); 15 int tot = s[1] == 'G', m = 0, tmp = 1; 16 for (int i = 2; i <= n; ++i) 17 { 18 tot += s[i] == 'G'; 19 if (s[i] != s[i - 1]) 20 { 21 a[++m] = pii(tmp, s[i] == 'G'); 22 tmp = 0; 23 } 24 ++tmp; 25 } 26 a[++m] = pii(tmp, s[n] != 'G'); 27 int res = 0; 28 for (int i = 1; i <= m; ++i) 29 { 30 if (a[i].second == 0) 31 res = max(res, min(tot, a[i].first + 1)); 32 else if (i != 1 && i != m && a[i].first == 1) 33 res = max(res, min(tot, a[i - 1].first + 1 + a[i + 1].first)); 34 } 35 printf("%d\n", res); 36 } 37 return 0; 38 }
C. Multi-Subject Competition
Solved.
題意:
有一個多學科競賽,一名隊員只會一門學科
派出去的隊伍對於每個要參加的學科其參加的人數要相等
並且每個隊員對於其會的那門學科有一個技能值
求如何派出隊伍參加學科使得隊伍中所有隊員的技能值總和最大。
思路:
列舉要參加的學科派出的隊員數,網上列舉,不符合條件的學科消除影響,每名隊員只會遍歷一次
時間複雜度$O(n)$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int n, m; 6 vector <int> v[N]; 7 int tot[N]; 8 queue <int> q; 9 10 int main() 11 { 12 while (scanf("%d%d", &n, &m) != EOF) 13 { 14 for (int i = 1; i <= m; ++i) v[i].clear(); 15 memset(tot, 0, sizeof tot); 16 while (!q.empty()) q.pop(); 17 for (int i = 1, s, r; i <= n; ++i) 18 { 19 scanf("%d%d", &s, &r); 20 v[s].push_back(r); 21 } 22 for (int i = 1; i <= m; ++i) sort(v[i].rbegin(), v[i].rend()); 23 for (int i = 1; i <= m; ++i) q.push(i); 24 int res = 0, tmp = 0; 25 for (int i = 1; ; ++i) 26 { 27 if (q.empty()) break; 28 for (int j = 1, len = q.size(); j <= len; ++j) 29 { 30 int top = q.front(); q.pop(); 31 tmp -= tot[top]; 32 if (v[top].size() < i) 33 continue; 34 tot[top] += v[top][i - 1]; 35 if (tot[top] <= 0) continue; 36 tmp += tot[top]; 37 q.push(top); 38 } 39 res = max(res, tmp); 40 } 41 printf("%d\n", res); 42 } 43 return 0; 44 }View Code
D. Maximum Diameter Graph
Solved.
題意:
給出一個n,和每個點最大的度數,構造一棵樹,使得每個點的度數不超過最大度數,並且直徑最長
思路:
如果所有點的度數之和小於$2 * (n - 1)$ 那麼就不可以構造
否則將所有度數$>= 2的點放到直徑上,再兩邊新增一個度為1的點(如果有)$
$剩下的點就連到這條直徑上還有度數剩餘的點上$
n給的好小,好懷疑自己的做法,當時。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 510 5 int n, a[N]; 6 vector <int> l, r; 7 8 int main() 9 { 10 while (scanf("%d", &n) != EOF) 11 { 12 int sum = 0; 13 l.clear(), r.clear(); 14 for (int i = 1; i <= n; ++i) 15 { 16 scanf("%d", a + i); 17 sum += a[i]; 18 if (a[i] > 1) l.push_back(i); 19 else r.push_back(i); 20 } 21 if (sum < 2 * (n - 1)) puts("NO"); 22 else 23 { 24 if (!r.empty()) l.insert(l.begin(), r.end()[-1]), r.pop_back(); 25 if (!r.empty()) l.push_back(r.end()[-1]), r.pop_back(); 26 printf("YES %d\n", (int)l.size() - 1); 27 printf("%d\n", n - 1); 28 for (int i = 1, len = l.size(); i < len; ++i) printf("%d %d\n", l[i], l[i - 1]), --a[l[i]], --a[l[i- 1]]; 29 for (int i = 0, j = 0, len1 = l.size(), len2 = r.size(); i < len2; ++i) 30 { 31 while (a[l[j]] == 0) ++j; 32 --a[l[j]]; 33 printf("%d %d\n", r[i], l[j]); 34 } 35 } 36 } 37 return 0; 38 }View Code
E. Increasing Frequency
Solved.
題意:
給出一個n個數,可以選取一段$[l, r], 使得區間內所有數都+k
$求最多進行一次這樣的操作,使得最後$a_i == c的個數最多$
求這個最多的個數
思路:
顯然一個區間的貢獻這個區間內相同數字最大的個數加上區間外c的個數,然後這樣區間列舉就是$O(n^2)$
我們可以考慮,列舉$a_i$ 即要把哪些數字變成$c$
那麼這時候,所有不是$c也不是a_i 的數字就沒有用$ 不妨把它們單獨拿出來考慮(類似於虛樹思想)
假設$L[i], R[i] 表i左邊的c的個數 和 i 右邊的c的個數$
那麼我假設序列中有$x個a(a 為列舉的a_i)$
$L[1], R[1], ... L[x], R[x]$
我們$需要找一個以後 x, y 使得 R[y] + (y - x + 1) + L[x] 最大$
$那麼可以列舉x ,然後即找一個最大的 (y - x + 1) + R[y]$
這個可以用線段樹維護。
發現常數項是遞增的,建樹的時候就可以給它,每次更新的時候,相當於後面的每一個都減一
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 500010 5 int n, c, a[N], dpl[N], dpr[N]; 6 vector <int> v[N]; 7 8 namespace SEG 9 { 10 int Max[N << 2], lazy[N << 2]; 11 void pushup(int id) { Max[id] = max(Max[id << 1], Max[id << 1 | 1]); } 12 void build(int now, int id, int l, int r) 13 { 14 Max[id] = lazy[id] = 0; 15 if (l == r) 16 { 17 Max[id] = l + dpr[v[now][l - 1]]; 18 return; 19 } 20 int mid = (l + r) >> 1; 21 build(now, id << 1, l, mid); 22 build(now, id << 1 | 1, mid + 1, r); 23 pushup(id); 24 } 25 void pushdown(int id) 26 { 27 if (!lazy[id]) return; 28 lazy[id << 1] += lazy[id]; 29 Max[id << 1] += lazy[id]; 30 lazy[id << 1 | 1] += lazy[id]; 31 Max[id << 1 | 1] += lazy[id]; 32 lazy[id] = 0; 33 } 34 void update(int id, int l, int r, int ql, int qr) 35 { 36 if (l >= ql && r <= qr) 37 { 38 --Max[id]; 39 --lazy[id]; 40 return; 41 } 42 int mid = (l + r) >> 1; 43 pushdown(id); 44 if (ql <= mid) update(id << 1, l, mid, ql, qr); 45 if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr); 46 pushup(id); 47 } 48 int query(int id, int l, int r, int ql, int qr) 49 { 50 if (l >= ql && r <= qr) return Max[id]; 51 int mid = (l + r) >> 1; 52 pushdown(id); 53 int res = 0; 54 if (ql <= mid) res = max(res, query(id << 1, l, mid, ql, qr)); 55 if (qr > mid) res = max(res, query(id << 1 | 1, mid + 1, r, ql, qr)); 56 return res; 57 } 58 } 59 60 void init() 61 { 62 for (int i = 1; i <= 500000; ++i) v[i].clear(); 63 } 64 65 int main() 66 { 67 while (scanf("%d%d", &n, &c) != EOF) 68 { 69 init(); 70 for (int i = 1; i <= n; ++i) scanf("%d", a + i), v[a[i]].push_back(i); 71 int tmp = 0; 72 for (int i = 1; i <= n; ++i) 73 { 74 dpl[i] = tmp; 75 tmp += a[i] == c; 76 } 77 tmp = 0; 78 for (int i = n; i >= 1; --i) 79 { 80 dpr[i] = tmp; 81 tmp += a[i] == c; 82 } 83 int res = 0; 84 for (int i = 1; i <= 500000; ++i) if (v[i].size()) 85 { 86 int len = v[i].size(); 87 SEG::build(i, 1, 1, len); 88 for (int j = 0; j < len; ++j) 89 { 90 res = max(res, dpl[v[i][j]] + SEG::query(1, 1, len, j + 1, len)); 91 SEG::update(1, 1, len, j + 1, len); 92 } 93 } 94 printf("%d\n", res); 95 } 96 return 0; 97 }View Code
F. Speed Dial
Unsolved.
G. Petya and Graph
Unsolved.