Codeforces Round #530 (Div. 2) Solution
A. Snowball
籤。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int w, h, u[2], d[2]; 5 6 int main() 7 { 8 while (scanf("%d%d", &w, &h) != EOF) 9 { 10 for (int i = 0; i < 2; ++i) scanf("%d%d", u + i, d + i); 11 for (int i = h; i >= 0View Code; --i) 12 { 13 w += i; 14 for (int j = 0; j < 2; ++j) if (i == d[j]) 15 { 16 w -= u[j]; 17 w = max(w, 0); 18 } 19 } 20 printf("%d\n", w); 21 } 22 return 0; 23 }
B. Squares and Segments
籤.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n; 5 int main() 6 { 7 while (scanf("%d", &n) != EOF) 8 { 9 int limit = sqrt(n); 10 int res = 1e9; 11 for (int i = 1; i <= limit; ++i) 12 res = min(res, i + n / i + (n % i ? 1View Code: 0)); 13 printf("%d\n", res); 14 } 15 return 0; 16 }
C. Postcard
Solved.
題意:
一個不定字串,
如果有一位上有糖果,那麼它前面那一個字元可以選擇留下獲得丟失
如果有一位上有雪花,那麼它前面那一個字元可以選擇留下、丟失或者重複x次,x自定
問能否由一種合法的選擇,使得確定後的字串的長度為n
思路:
先排除兩種情況,
第一種是去掉所有可以去掉的字元後,長度都大於n
第二種是保留所有的不定字元,並且沒有雪花,此時長度小於n
那麼其他情況都是可以構造的
考慮兩種情況
第一種 沒有雪花,那麼只需要刪掉一些字元使得滿足題意,不合法情況在之前已經排除
第二種 有雪花,保留一個雪花字元,刪掉其他字元,用雪花字元的重複來填充長度
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1010 5 char s[N]; 6 int n, len; 7 8 int main() 9 { 10 while (scanf("%s", s + 1) != EOF) 11 { 12 scanf("%d", &n); 13 len = strlen(s + 1); 14 int snow = 0, candy = 0; 15 for (int i = 1; i <= len; ++i) 16 { 17 if (s[i] == '*') ++snow; 18 if (s[i] == '?') ++candy; 19 } 20 if (len - 2 * (snow + candy) > n) puts("Impossible"); 21 else if (len - candy < n && snow == 0) puts("Impossible"); 22 else 23 { 24 string res = ""; 25 if (snow == 0) 26 { 27 int needdel = len - candy - n; 28 for (int i = 1; i <= len; ++i) 29 { 30 if (s[i] == '?') continue; 31 if (i != len && s[i + 1] == '?') 32 { 33 if (needdel) --needdel; 34 else res += s[i]; 35 } 36 else res += s[i]; 37 } 38 } 39 else 40 { 41 int flag = true; 42 int needadd = n - (len - 2 * (candy + snow)); 43 for (int i = 1; i <= len; ++i) 44 { 45 if (i != len && s[i + 1] == '?') continue; 46 if (i != len && s[i + 1] == '*' && !flag) continue; 47 if (s[i] == '?' || s[i] == '*') continue; 48 if (i != len && s[i + 1] == '*') 49 { 50 flag = false; 51 while (needadd--) res += s[i]; 52 } 53 else res += s[i]; 54 } 55 } 56 cout << res << endl; 57 } 58 } 59 return 0; 60 }View Code
D. Sum in the tree
Solved.
題意:
有一棵樹,有點權,知道奇數層所有點的到根的字首點權和,偶數層的不知道
求如何分配點權使得滿足限制條件並且所有點權和最小
思路:
儘量將點權分配給深度低的,因為這樣它產生的貢獻肯定比分給深度大的要高
那麼一個偶數層點u最多可以分配的點權就是
$Min(s[v] - s[fa[u]])\ v為它的兒子$
判-1也很好判,上面這個Min值如果是負的就不行,因為點權大於等於0
對於奇數層點的話 直接算它點權
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 int n, s[N]; 7 vector <int> G[N]; 8 bool flag; ll res; 9 10 ll dist[N]; 11 void DFS(int u, int fa) 12 { 13 if (s[u] == -1) 14 { 15 if (G[u].size() == 1) return; 16 ll Min = (ll)1e18; 17 for (auto v : G[u]) if (v != fa) 18 Min = min(Min, s[v] - dist[fa]); 19 if (Min < 0) 20 { 21 flag = false; 22 return; 23 } 24 res += Min; 25 dist[u] = dist[fa] + Min; 26 } 27 else 28 { 29 dist[u] = s[u]; 30 res += dist[u] - dist[fa]; 31 } 32 for (auto v : G[u]) if (v != fa) 33 { 34 DFS(v, u); 35 if (!flag) return; 36 } 37 } 38 39 int main() 40 { 41 while (scanf("%d", &n) != EOF) 42 { 43 flag = true; res = 0; 44 for (int i = 1; i <= n; ++i) G[i].clear(); 45 for (int i = 2, p; i <= n; ++i) 46 { 47 scanf("%d", &p); 48 G[i].push_back(p); 49 G[p].push_back(i); 50 } 51 for (int i = 1; i <= n; ++i) scanf("%d", s + i); 52 DFS(1, 0); 53 if (!flag) res = -1; 54 printf("%lld\n", res); 55 } 56 return 0; 57 }View Code
F. Cookies
Upsolved.
題意:
剛開始有一個砝碼在根節點,兩個玩家,
先手玩家可以選擇將它移向它的某個兒子,
後手玩家可以選擇移除掉通向它某個兒子的邊,當然也可以選擇跳過這個操作
先手玩家可以選擇在什麼時候停下來,並且回到根節點,回去的過程可以吃餅乾
每個結點有餅乾數量,以及吃掉該節點上的一塊餅乾需要的時間
吃餅乾需要時間,在邊上走也需要時間,總時間T的情況下吃到的最多的餅乾
求雙方都在最優操作下,先手玩家吃到的餅乾的最多的數量
思路:
先處理出每個結點回去的答案,再二分答案,十分顯然
怎麼處理答案,
對於點u, 首先吃餅乾的時間是$T - 2 * dist(root, u)$
那麼用權值BIT維護時間,以及餅乾數量,二分查詢在剩餘時間的可以吃的最大餅乾數量
注意處理尾部的部分
再二分答案,dp驗證
考慮什麼樣的情況是合理的,我們假定某一個點是必勝態,那麼這個點的深度如果<=1,
那麼先手必勝,因為先手先移動
再考慮哪些點是必勝態,如果該點的處理出的餅乾數量$ > limit$ 那麼就是必勝態
又或者該點有2個兒子以上的點是必勝態,該點也是必勝態,因為後手玩家每次只能刪去一條邊
遞迴判斷即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 #define M 1000010 7 int n; ll T; 8 int x[N], t[N], l[N]; 9 vector <int> G[N]; 10 11 namespace BIT 12 { 13 ll val[M], sum[M], a[M]; 14 void init() 15 { 16 memset(val, 0, sizeof val); 17 memset(sum, 0, sizeof sum); 18 memset(a, 0, sizeof a); 19 } 20 void update(int x, ll v) 21 { 22 ll sumv = v * x; 23 a[x] += v; 24 for (; x < M; x += x & -x) 25 { 26 val[x] += v; 27 sum[x] += sumv; 28 } 29 } 30 ll query(ll T) 31 { 32 int l = 0, r = M - 5; 33 ll res = 0; 34 while (r - l >= 0) 35 { 36 int mid = (l + r) >> 1; 37 int x = mid; 38 ll score = 0, sumt = 0; 39 for (; x; x -= x & -x) 40 { 41 score += val[x]; 42 sumt += sum[x]; 43 } 44 if (sumt <= T) 45 { 46 score += min(a[mid + 1], ((T - sumt) / (mid + 1))); 47 res = score; 48 l = mid + 1; 49 } 50 else 51 r = mid - 1; 52 } 53 return res; 54 } 55 } 56 57 int fa[N], deep[N]; 58 ll dist[N], score[N]; 59 void DFS(int u) 60 { 61 for (auto v : G[u]) if (v != fa[u]) 62 { 63 deep[v] = deep[u] + 1; 64 dist[v] = dist[u] + l[v]; 65 BIT::update(t[v], x[v]); 66 score[v] = BIT::query(T - 2ll * dist[v]); 67 DFS(v); 68 BIT::update(t[v], -x[v]); 69 } 70 } 71 72 bool vis[N]; 73 void dp(int u, ll x) 74 { 75 if (score[u] >= x) 76 { 77 vis[u] = 1; 78 return; 79 } 80 int cnt = 0; 81 for (auto v : G[u]) if (v != fa[u]) 82 { 83 dp(v, x); 84 cnt += vis[v]; 85 } 86 if (cnt >= 2) vis[u] = 1; 87 } 88 89 bool check(ll x) 90 { 91 memset(vis, 0, sizeof vis); 92 dp(1, x); 93 for (int i = 1; i <= n; ++i) if (deep[i] <= 1 && vis[i]) 94 return 1; 95 return 0; 96 } 97 98 void init() 99 { 100 for (int i = 1; i <= n; ++i) G[i].clear(); 101 BIT::init(); 102 } 103 104 int main() 105 { 106 while (scanf("%d%lld", &n, &T) != EOF) 107 { 108 init(); 109 for (int i = 1; i <= n; ++i) scanf("%d", x + i); 110 for (int i = 1; i <= n; ++i) scanf("%d", t + i); 111 for (int i = 2; i <= n; ++i) 112 { 113 scanf("%d%d", fa + i, l + i); 114 G[i].push_back(fa[i]); 115 G[fa[i]].push_back(i); 116 } 117 BIT::update(t[1], x[1]); score[1] = BIT::query(T); dist[1] = 0; deep[1] = 0; 118 DFS(1); 119 ll l = 0, r = (ll)1e11 + 10, res = 0; 120 while (r - l >= 0) 121 { 122 ll mid = (l + r) >> 1; 123 if (check(mid)) 124 { 125 res = mid; 126 l = mid + 1; 127 } 128 else 129 r = mid - 1; 130 } 131 printf("%lld\n", res); 132 } 133 return 0; 134 }View Code