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
", 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
", 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
", res);
55     }
56     return 0;
57 }
View Code

E. Nice table

Upsolved.

题意:

构造一个$n * m的字符串矩阵,只包含'A', 'G', 'C', 'T'$

使得$任意2 cdot 2 的子矩形都包含'A', 'G', 'C', 'T'$

并且要与给出的矩阵不同的字符个数最少

思路:

要求满足$任意2 cdot 2 的子矩形都包含'A', 'G', 'C', 'T'$

的矩阵要满足每一行都是由两个字符交替组成

或者每一列都是由两个字符交替组成

枚举即可

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define N 150010
  5 int n, m, p;
  6 string s[N];
  7 string t[2][6] = 
  8 {
  9     {
 10         "AG",
 11         "AC",
 12         "AT",
 13         "GC",
 14         "GT",
 15         "CT",
 16     },    
 17     {
 18         "CT",
 19         "GT",
 20         "CG",
 21         "AT", 
 22         "AC",
 23         "AG",
 24     }
 25 };
 26 string res[12][N];    
 27 
 28 void work_row(string a, string b)
 29 {
 30     for (int i = 0; i < n; ++i) res[p][i].clear();
 31     string tmp[2];
 32     int cnt[2];
 33     for (int i = 0; i < n; ++i) 
 34     {
 35         tmp[0] = tmp[1] = "";
 36         cnt[0] = cnt[1] = 0;
 37         for (int j = 0; j < m; ++j) 
 38             for (int k = 0; k < 2; ++k)
 39                 tmp[k] += (i & 1) ? a[j % 2 ^ k] : b[j % 2 ^ k];    
 40         for (int j = 0; j < m; ++j)
 41             for (int k = 0; k < 2; ++k)
 42                 cnt[k] += tmp[k][j] != s[i][j]; 
 43         if (cnt[0] < cnt[1])
 44             res[p][i] = tmp[0];
 45         else 
 46             res[p][i] = tmp[1]; 
 47     }
 48     ++p;
 49 }
 50 
 51 void work_col(string a, string b)
 52 {
 53     for (int i = 0; i < n; ++i) res[p][i].clear();
 54     string tmp[2];
 55     int cnt[2];
 56     for (int j = 0; j < m; ++j)
 57     {
 58         tmp[0] = tmp[1] = "";
 59         cnt[0] = cnt[1] = 0;
 60         for (int i = 0; i < n; ++i) 
 61             for (int k = 0; k < 2; ++k)
 62                 tmp[k] += (j & 1) ? a[i % 2 ^ k] : b[i % 2 ^ k];
 63         for (int i = 0; i < n; ++i)
 64             for (int k = 0; k < 2; ++k)
 65                 cnt[k] += tmp[k][i] != s[i][j];
 66         if (cnt[0] < cnt[1])
 67             for (int i = 0; i < n; ++i)
 68                 res[p][i] += tmp[0][i];
 69         else
 70             for (int i = 0; i < n; ++i)
 71                 res[p][i] += tmp[1][i];
 72     }
 73     ++p;
 74 }
 75 
 76 int com(int x)
 77 {
 78     int tmp = 0;
 79     for (int i = 0; i < n; ++i) 
 80         for (int j = 0; j < m; ++j)
 81             tmp += res[x][i][j] != s[i][j];
 82    return tmp;    
 83 }
 84 
 85 int main()
 86 {
 87     ios::sync_with_stdio(false);
 88     cin.tie(0); cout.tie(0);
 89     while (cin >> n >> m)
 90     {
 91         p = 0;
 92         for (int i = 0; i < n; ++i) cin >> s[i];
 93         for (int i = 0; i < 6; ++i)
 94             work_row(t[0][i], t[1][i]);
 95         for (int i = 0; i < 6; ++i)
 96             work_col(t[0][i], t[1][i]);
 97         int Min = (int)1e9, pos = -1;
 98         for (int i = 0; i < 12; ++i)
 99         {
100             //puts("bug");
101             //for (int j = 0; j < n; ++j) cout << res[i][j] << "
";
102             int tmp = com(i);
103             //cout << tmp << "
";
104             if (tmp < Min)
105             {
106                 Min = tmp;
107                 pos = i;
108             }
109         }
110         for (int i = 0; i < n; ++i) cout << res[pos][i] << "
";
111     }
112     return 0;
113 }
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
", res);
132     }    
133     return 0;
134 }
View Code
原文地址:https://www.cnblogs.com/Dup4/p/10227106.html