牛客周赛 Round 70
小苯晨跑
思路
判全部是否相等即可。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int a[5]{}; for(int i = 0;i < 4;i ++){ cin >> a[i]; } for(int i = 1;i < 4;i ++){ if(a[i] != a[i - 1]){ cout << "YES\n"; return ; } } cout << "NO\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
小苯过马路
思路
分类讨论。
- 当前是绿灯的时候:
- 剩下的时间够通过马路:则花费 \(t\) 时间。
- 剩下的时间不够过马路,需等到下一次绿灯,中间等一次红灯:花费 \(t + k + x\) 时间。
- 当前是红灯:直接等到绿灯即可:花费 \(k + t\) 时间。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int x,y,k,t; char c; cin >> x >> y >> k >> t >> c; if(c == 'G'){ if(k >= t){ cout << t << "\n"; }else{ cout << t + k + x << "\n"; } }else{ cout << k + t << "\n"; } return 0; }
小苯的字符串染色
思路
因为区间长度为 \(1\) 的染色为白色,且构造次数小于等于 \(n\) 次,那么直接对每个 \(i\) 染色即可。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n; cin >> n; string s; cin >> s; cout << n << "\n"; for(int i = 1;i <= n;i ++){ cout << i << " " << i << "\n"; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
小苯的能量项链
思路
因为每次操作都会去掉一个数,所以我们最后能保留下来的数最少是 \(\max(2,n-k)\) 个,在这个区间两边的都有可能被保留下来,那么我们只要维护这个区间两边的最大值即可,即预处理一遍前缀后缀最大值。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n, k; cin >> n >> k; vector<int> a(n + 1); for (int i = 1; i <= n; i ++) { cin >> a[i]; } if (n == 1) { cout << a[1] << "\n"; return ; } vector<int> pre(n + 1), suf(n + 1); pre[1] = a[1], suf[n] = a[n]; for (int i = 2; i <= n; i ++) { pre[i] = max(a[i], pre[i - 1]); } for (int i = n - 1; i >= 1; i --) { suf[i] = max(suf[i + 1], a[i]); } int ans = 0; int len = max(2, n - k); for (int i = 1; i + len - 1 <= n; i ++) { ans = max(ans, pre[i] + suf[i + len - 1]); } cout << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
小苯的最短路
思路
结论题,然而我是通过打表发现的。
一共用了两个结论。
结论 \(1\) :\(1\oplus i \le 1\oplus j + j \oplus i.\)
由已知结论 \(a \oplus b \le a + b,0\oplus x=x,x\oplus x=0\) ,简单证明上述结论:
所以由上述结论可知,从 \(1\) 出发的最短路一定是 \(1\) 直达最短,不用中转。
所以最后的最短路的值的异或和即答案为 \(\bigoplus\limits_{i=1}^ni\),这个也同样有个结论,证明[1]网上也能搜到,在此不过多赘述。
结论 \(2\) :设 \(x=\bigoplus\limits_{i=1}^ni\),则有:
- 当 \(x \equiv 0\pmod 4,x=n.\)
- 当 \(x \equiv 1\pmod 4,x=1.\)
- 当 \(x \equiv 2\pmod 4,x=n+1.\)
- 当 \(x \equiv 3\pmod 4,x=0.\)
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n; cin >> n; if (n & 1) { n--; cout << (n % 4 !=0) << "\n"; } else { cout << n + (n % 4 != 0) << "\n"; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
小苯的优雅好序列
思路
要使得所有的连续子数组都满足优雅的,那么可以得出一个结论:
- 对于相邻的 \(a_i\) 和 \(a_{i+1}\) 一定满足 \(a_i \mid a_{i+1}\) 或者 \(a_{i+1} \mid a_i\)。
简单证明:子数组长度为 \(1\) 时,显然满足条件;子数组长度为 \(2\) 时,要使得其优雅,也就是这两个数之间要满足整除关系,由此可得该结论。
现在问加上一个 \(x\) 后是否满足该数组是一个好数组,那么同样也可以得到一个结论:
- 相邻两数之间的差值都满足是较小数加上 \(x\) 的倍数。
设相邻两数为 \(a,b\),有 \(a\le b\),简单证明:
所以对于一个 \(x\),要判断数组都加上它后是否是一个好数组,那么只要 \(O(n)\) 检查一遍上述结论即可。
那么还有一个问题,检查的范围,总不能对 \(1\sim k\) 都检查一遍吧。
还是利用上面的结论,通过上述结论可以发现,所有的相邻数都应该满足这样一个结论,那么我们只要找任意一组相邻且不相等的两数,把它们的差值拿出验证其他相邻对是否满足这样一个关系即可。
复杂度 \(O(\sqrt{\max a_i}\times n)\),\(1\sim 1\times 10^9\) 以内最大的因子数为 \(1344\),实际上并不会跑满。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n, k; cin >> n >> k; array<int, 2> has{0,0}; vector<int> a(n + 1); for (int i = 1; i <= n; i ++) { cin >> a[i]; if (i > 1&& a[i] != a[i - 1]) { has = {a[i - 1], a[i]}; } } int d = abs(has[0] - has[1]); if (d == 0) { cout << k << " " << 1LL * k * (k + 1) / 2 << "\n"; return ; } i64 cnt = 0, ans = 0; auto check = [&](int x)->void{ x -= min(has[0], has[1]); if (x <= 0) { return ; } auto ok = [&](int pos, int idx)->bool{ if (idx < 1 || idx > n) return false; int s = abs(a[pos] - a[idx]); return s % (a[pos] + x) == 0 || s % (a[idx] + x) == 0; }; for (int i = 1; i <= n; i ++) { if (!ok(i, i + 1) && !ok(i, i - 1)) { return ; } } if (x > k) return; cnt ++ , ans += x; }; for (int i = 1; i <= d / i; i ++) { if (d % i == 0) { check(i); if (i != d / i) { check(d / i); } } } cout << cnt << " " << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
小苯的树上操作
思路
赛时没写出来,参考下官方题解[2]。
设 \(dp_i\) 表示以 \(i\) 为根,删除若干结点后得到的最大子树和。
对于结点 \(u\) 来说,如果不删除结点 \(u\),那么 \(dp_u=\sum\limits_{v\in S}dp_v[dp_v\ge 0]\) (\(S\) 代表 \(u\) 的子树);如果删除除结点 \(i\) 以外的根结点 \(u\),那么由于要删除度数恰好为 \(2\) 的,所以最多只能保留一棵子树,即 \(dp_u=\max(0,\max\limits_{v\in S}dp_v)\)。
特别的,把根结点删除后,其实是最多两棵子树的合并,所以维护答案 \(f_u\) 表示以 \(u\) 为根的答案,那么从 \(f_u\) 转移到 \(f_v\) 的过程,可以维护一个值 \(up\),表示父结点 \(u\) 删掉除去子结点 \(v\) 后剩下子树的最大子树和,和 \(dp_i\) 的计算方法类似,只不过放到了递归中去维护。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n; cin >> n; vector<int> a(n + 1); for (int i = 1; i <= n; i ++) { cin >> a[i]; } vector g(n + 1, vector<int>()); for (int i = 1; i < n; i ++) { int u, v; cin >> u >> v; g[u].emplace_back(v); g[v].emplace_back(u); } vector<i64> dp(n + 1); auto dfs = [&](auto && self, int u, int fa)->void{ dp[u] += a[u]; multiset<i64, greater<>> s; for (auto &v : g[u]) { if (v == fa)continue; self(self, v, u); dp[u] += dp[v] * (dp[v] > 0); s.insert(dp[v]); } dp[u] = max({dp[u], 0LL, *s.begin()}); }; dfs(dfs, 1, 0); vector<i64> f(n + 1); auto dfs1 = [&](auto && self, int u, int fa, i64 up)->void{ i64 all = a[u] + up; multiset<i64, greater<>> s; s.insert(up); for (auto &v : g[u]) { if (v == fa)continue; all += dp[v] * (dp[v] > 0); s.insert(dp[v]); } f[u] = max(all, *s.begin() + (s.size() > 1 ? *next(s.begin()) : 0LL)); for (auto &v : g[u]) { if (v == fa)continue; s.erase(s.lower_bound(dp[v])); self(self, v, u, max(all - dp[v], s.size() ? *s.begin() : 0LL)); s.insert(dp[v]); } }; dfs1(dfs1, 1, 0, 0); cout << *max_element(f.begin() + 1, f.end()) << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
本文作者:Ke_scholar
本文链接:https://www.cnblogs.com/Kescholar/p/18590405
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步