牛客比赛笔记(1)

1、牛客小白月赛45

A

注意即使跳不到对面也得跳一次。

1 int main()
2 {
3     int x, n; read(x, n);
4     cout << (n > x ? x : 1ll * n * x);
5     fwrite(pbuf, 1, pp - pbuf, stdout); return 0;
6 }
View Code

B

显然答案是 $n^2$。

1 int main()
2 {
3     int n; read(n);
4     cout << 1ll * n * n;
5     fwrite(pbuf, 1, pp - pbuf, stdout); return 0;
6 }
View Code

C

显然合并 $4$ 个对之后的贡献不优,所以优先合并 $3$ 个,剩下了再凑成 $4$ 个。

 1 int main()
 2 {
 3     ll a[10], ans = 0;
 4     for (int i = 1; i <= 8; ++i) read(a[i]);
 5     for (int i = 1; i <= 8; ++i)
 6     {
 7         if (a[i] < 3) continue;
 8         if (a[i] == 5) ans += i << 2, ++a[i + 1];
 9         else ans += a[i] * i, a[i + 1] += a[i] / 3;
10     }
11     cout << ans;
12     fwrite(pbuf, 1, pp - pbuf, stdout); return 0;
13 }
View Code

D

直接 DP 即可,实际上答案是 $2^k$ 的形式,注意一定要中途判断括号串是否合法。

 1 const int N = 1e6 + 10;
 2 const ll p = 1e9 + 7;
 3 char s[N];
 4 ll dp[N];
 5 
 6 int main()
 7 {
 8     scanf("%s", s + 1);
 9     int n = strlen(s + 1), tmp = 0; ll sum = 1;
10     for (int i = 1; i <= n; ++i)
11     {
12         s[i] == '(' ? ++tmp : --tmp;
13         if (tmp < 0) { cout << -1; return 0; }
14         if (!tmp) dp[i] = sum, (sum += dp[i]) %= p;
15     }
16     if (!n) cout << 1;
17     else if (tmp) cout << -1;
18     else cout << dp[n];
19     fwrite(pbuf, 1, pp - pbuf, stdout); return 0;
20 }
View Code

E

直接树形 DP 即可,注意答案初始化为 $-\infty$。

 1 const int N = 1e5 + 10;
 2 int n, a[N];
 3 ll ans = -1e18, dp[N];
 4 struct edge { int v, w; };
 5 vector<edge> vec[N];
 6 
 7 void dfs(int u, int fa)
 8 {
 9     dp[u] = a[u], ans = Max(ans, dp[u]);
10     for (int i = 0; i < vec[u].size(); ++i)
11     {
12         int v = vec[u][i].v, w = vec[u][i].w;
13         if (v == fa) continue; dfs(v, u);
14         dp[u] = Max(dp[u], dp[u] + dp[v] + w);
15         ans = Max(ans, dp[u]);
16     }
17 }
18 
19 int main()
20 {
21     read(n); for (int i = 1; i <= n; ++i) read(a[i]);
22     for (int u, v, w, i = 1; i < n; ++i)
23     {
24         read(u, v, w); vec[u].emplace_back((edge){v, w});
25         vec[v].emplace_back((edge){u, w});
26     }
27     dfs(1, 0); cout << ans;
28     fwrite(pbuf, 1, pp - pbuf, stdout); return 0;
29 }
View Code

F

直接暴力预处理答案即可,但是出题人毒瘤卡 unordered_map 和 map,需要用 Trie 树卡常。

 1 const int N = 2e3 + 10;
 2 const int S = 3.63e7;
 3 int n, m, tot, x[N], y[N], trie[S][11], ans[S];
 4 
 5 inline void ins(int *a, const int &k, const int &tmp)
 6 {
 7     int p = 0;
 8     for (int i = 1; i <= k; ++i)
 9     {
10         if (!trie[p][a[i]]) trie[p][a[i]] = ++tot;
11         p = trie[p][a[i]];
12     }
13     ans[p] = Min(ans[p], tmp);
14 }
15 inline int get(int *a, const int &k)
16 {
17     int p = 0;
18     for (int i = 1; i <= k; ++i)
19     {
20         if (!trie[p][a[i]]) return -1;
21         p = trie[p][a[i]];
22     }
23     return ans[p];
24 }
25 
26 int main()
27 {
28     read(n, m); int a[11]; memset(ans, 0x3f, sizeof(ans));
29     for (int i = 1; i <= n; ++i) read(x[i], y[i]);
30     for (int i = 1; i <= 10; ++i) a[i] = i, ins(a, i, 0);
31     for (int r = 1; r <= n; ++r)
32     {
33         for (int i = 1; i <= 10; ++i) a[i] = i;
34         for (int l = r; l; --l)
35         {
36             swap(a[x[l]], a[y[l]]);
37             for (int i = 1; i <= 10; ++i) ins(a, i, r - l + 1);
38         }
39     }
40     while (m--)
41     {
42         int k; read(k);
43         for (int i = 1; i <= k; ++i) read(a[i]);
44         cout << get(a, k) << '\n';
45     }
46     fwrite(pbuf, 1, pp - pbuf, stdout); return 0;
47 }
View Code

2、牛客练习赛97

A

奇偶数分别排序即可。

 1 const int N = 110;
 2 int n, a[N], b[N], c[N], d[N];
 3 
 4 int main()
 5 {
 6     read(n);
 7     for (int i = 1; i <= n; ++i)
 8     {
 9         read(a[i]);
10         if (a[i] & 1) b[++b[0]] = a[i], d[i] = 1;
11         else c[++c[0]] = a[i], d[i] = 0;
12     }
13     sort(b + 1, b + b[0] + 1), sort(c + 1, c + c[0] + 1);
14     for (int p = 0, q = 0, i = 1; i <= n; ++i)
15     {
16         d[i] ? a[i] = b[++p] : a[i] = c[++q];
17         if (a[i] < a[i - 1]) { puts("No"); return 0; }
18     }
19     puts("Yes");
20     flush_pbuf(); return 0;
21 }
View Code

B

诈骗题,考虑如果二进制位的最高位 $1$ 确定了之后,加入新的数必然会使 $\operatorname{or}$ 和的某些位 $0\rightarrow1$ 但 $\operatorname{and}$ 和的某些位 $1\rightarrow0$,但是不难发现 $1\rightarrow0$ 的位一定不低于 $0\rightarrow1$ 的位,所以从大到小加的数越多答案越不优,因此答案就是只选一个数 $\max{\{a_i\}}$。

 1 const int N = 1e5 + 10;
 2 int n, maxv, a[N];
 3 
 4 int main()
 5 {
 6     read(n);
 7     for (int i = 1; i <= n; ++i)
 8         read(a[i]), maxv = Max(maxv, a[i]);
 9     print(maxv << 1);
10     flush_pbuf(); return 0;
11 }
View Code

C

实际上就是取某些格子使得权值和最大,用堆维护最大值即可,但是要注意不能踩和翻同一个格子,需要拆贡献,细节较多。

 1 const int N = 1e5 + 10;
 2 int n, m, a[N], b[N], p[N];
 3 bool vis[N];
 4 struct node
 5 {
 6     int x, v, t;
 7     node() {}
 8     node(int _x, int _v, int _t) : x(_x), v(_v), t(_t) {}
 9     inline bool operator < (const node &x) const { return v < x.v; }
10 };
11 priority_queue<node> q;
12 
13 int main()
14 {
15     read(n, m); ll ans = 0;
16     for (int i = 1; i <= n; ++i) read(a[i]);
17     for (int i = 1; i <= n; ++i) read(p[i]);
18     for (int i = 1; i <= n; ++i) read(b[i]);
19     
20     int k = m; ll tmp = 0;
21     for (int i = 1; i <= n; ++i)
22         if (!b[i])
23             if (a[i] <= 0) q.push(node(i, -p[i], 1));
24             else q.push(node(i, a[i], 0)), q.push(node(i, -p[i] - a[i], 1));
25         else q.push(node(i, a[i] - p[i], 1)), q.push(node(i, -p[i], 1));
26     while (!q.empty())
27     {
28         int x = q.top().x, v = q.top().v, t = q.top().t; q.pop();
29         if (v <= 0) break;
30         if (t && !k) continue;
31         if (b[x] && vis[x]) continue;
32         vis[x] = true, tmp += v; if (t) --k;
33     }
34     ans = Max(ans, tmp);
35     
36     memset(vis, false, sizeof(vis));
37     k = m, tmp = 0, priority_queue<node>().swap(q);
38     for (int i = 1; i <= n; ++i)
39         if (b[i])
40             if (a[i] <= 0) q.push(node(i, -p[i], 1));
41             else q.push(node(i, a[i], 0)), q.push(node(i, -p[i] - a[i], 1));
42         else q.push(node(i, a[i] - p[i], 1)), q.push(node(i, -p[i], 1));
43     while (!q.empty())
44     {
45         int x = q.top().x, v = q.top().v, t = q.top().t; q.pop();
46         if (v <= 0) break;
47         if (t && !k) continue;
48         if (!b[x] && vis[x]) continue;
49         vis[x] = true, tmp += v; if (t) --k;
50     }
51     ans = Max(ans, tmp);
52     
53     print(ans);
54     flush_pbuf(); return 0;
55 }
View Code

D

树上 DP,但如果讨论根节点的特殊颜色是什么会非常难做,考虑下放状态,忽略根节点的特殊颜色只看子节点就很好做了。

 1 const int N = 1e6 + 10;
 2 const ll p = 998244353;
 3 int n;
 4 vector<int> vec[N];
 5 ll x, y, dp[N][2];
 6 
 7 void dfs(int u, int fa)
 8 {
 9     dp[u][0] = dp[u][1] = 1;
10     for (int i = 0; i < vec[u].size(); ++i)
11     {
12         int v = vec[u][i]; if (v == fa) continue; dfs(v, u);
13         dp[u][0] = (x * dp[v][0] + y * dp[v][1]) % p * dp[u][0] % p;
14         dp[u][1] = (x * dp[v][0] + (y - 1) * dp[v][1]) % p * dp[u][1] % p;
15     }
16 }
17 
18 int main()
19 {
20     read(n, x, y);
21     for (int u, v, i = 1; i < n; ++i)
22         read(u, v), vec[u].emplace_back(v), vec[v].emplace_back(u);
23     dfs(1, 0); print((x * dp[1][0] + y * dp[1][1]) % p);
24     flush_pbuf(); return 0;
25 }
View Code

E

F

G

To be continued...

posted @ 2022-03-05 17:45  jhqqwq  阅读(19)  评论(0编辑  收藏  举报