1. 程式人生 > >Codeforces Round #530 (Div. 2) Solution

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 >= 0
; --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 }
View Code

 

 

 

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 ? 1
: 0)); 13 printf("%d\n", res); 14 } 15 return 0; 16 }
View Code

 

 

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