牛客比赛笔记(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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
E
F
G
To be continued...