蔚来杯2022牛客暑期多校训练营6 ABGJM
A
题解
知识点:数学,构造。
题目要求构造一个长为 的序列 , 自选,使得 的无限循环序列 中任意连续 个数中都存在数 。因此,容易想到从起点 开始每隔 个数就填一次 ,即在位置 ,由此确定了构造的基本方法是填数。
但显然,直接挨个填数很可能会使得某个数的某个落点已经被其他数占据了。比如当 时,考虑构造 的序列:先填 得到 ,再填 得到 ,发现下一个位置是 ,已经有数字了。然而事实上,我们不容易在较小的时间复杂度内得到一个合适的起点,使得这个数的落点不会被其他数占据。因此,考虑调整 ,使得我们可以容易避免落点重合的情况。
证明1
显然,我们只能缩小 使得,因为缩小后的 满足时原来的 一定满足,而放大不一定。
注意到,对于任意两个数 与 , 当 ,若 ,使得 ,则有 ,于是对于 ,都有 ,即处处重合。
因此,当 ,只要一处不重合,则所有落点都不重合。为了方便,将 缩小成小于等于它的最大的 的幂 。
但仅仅是这样只能保证两两不重合,还无法保证全都不重合。比如当 ,考虑 ,按顺序填,填到 时会发现 ,下一个位置是 ,还是被占据了。因此考虑改变填数顺序,使得后一个填的数不会被前面所有的数的位置影响。
证明2
从大到小的就是上述情况,不可行。
考虑从小到大,每次在第一个空位开始填。
由于每次都是从第一个空位填,所以不允许某个 前面填了大于等于 个位置,否则必然会循环回来落到开头被占据的位置,如上述情况。只要我们证明,对于任意一个 ,其前方已经填的位置数 ,即可。
由于 ,又条件告诉我们有 ,那么现在有 。
当填到 时,我们尝试构造 ,使得从 开始连续占用最多的位置。注意到,如果 ,则使用 等效于使用了 个 ,且总和 也是等价的 ,所以我们按这个方法,无论怎么取,最优结果都是一样的。因此在 下,为了方便,我们可以优先用小的 构造,快速缩小可行范围。
显然,我们只能构造 ,其倒数总和刚好是 ,而连续占用位置是 个。
于是我们证明了这个结论。
到这里其实最难的两个证明已经结束了。接下来我们思考一下 到底取多少合适。
证明3
长度 时占位为 ,因为每个 对应的 至少出现一次,可得 。
令 ,带入得 ,因此 是最小长度。
由于可能多出空位,但是可以随便填,所以全填 。
到此这道构造题就完全结束了。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; struct node { int val; int id; }a[100007]; int c[1000007]; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1;i <= n;i++) { cin >> a[i].val; a[i].id = i; int tmp = 1 << 30; while (tmp > a[i].val) tmp >>= 1; a[i].val = tmp; }///使用2的幂,证明1 sort(a + 1, a + n + 1, [&](node a, node b) { return a.val < b.val; });///从小到大,证明2 int m = a[n].val;///c的长度,证明3 for (int i = 1, pos = 0;i <= n;i++) { for (int j = pos;j < m;j += a[i].val) c[j] = a[i].id;///方法是填数 while (c[pos]) pos++; } cout << m << '\n'; for (int i = 0;i < m;i++) cout << max(1, c[i]) << ' ';///可能多出来空位随便填 cout << '\n'; return 0; }
B
题解
知识点:枚举,前缀和,差分,树。
考虑树上前缀和与差分。维护当前递归的一条树链的深度到节点编号的映射数组 即可差分,最后递归求前缀和。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; vector<int> g[2000007]; int d[2000007]; int dep[2000007], depL[2000007];///节点深度,一条链上深度对应节点 int sum[2000007];///树上差分 void dfs(int u, int fa) { dep[u] = dep[fa] + 1; depL[dep[u]] = u; sum[u]++; sum[depL[max(0, dep[u] - d[u] - 1)]]--; for (auto v : g[u]) { if (v == fa) continue; dfs(v, u); } } void cal(int u, int fa) { for (auto v : g[u]) { if (v == fa) continue; cal(v, u); sum[u] += sum[v]; } } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1;i < n;i++) { int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } for (int i = 1;i <= n;i++) cin >> d[i]; dfs(1, 0); cal(1, 0); for (int i = 1;i <= n;i++) cout << sum[i] << ' '; cout << '\n'; return 0; }
G
题解
知识点:模拟。
签到题。直接打表也行,模拟也行。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1;i <= 13 * n + 19;i++) cout << '*'; cout << '\n'; for (int i = 1;i <= n;i++) { cout << "*"; for (int j = 2;j <= 13 * n + 18;j++) cout << "."; cout << "*"; cout << '\n'; } for (int i = 1;i <= 2 * n + 3;i++) { cout << "*"; for (int j = 1;j <= n + 1;j++) cout << "."; for (int j = 1;j <= 2 * n + 3;j++) { if (i == 1 || i == 2 * n + 3) { if (j == 1 || j == 2 * n + 3) cout << "@"; else cout << "."; } else { if (j == 1 || j == 2 * n + 3 || j == i) cout << "@"; else cout << "."; } } for (int j = 1;j <= n + 1;j++) cout << "."; for (int j = 1;j <= 2 * n + 3;j++) { if (i == 1 || i == n + 2) cout << "@"; else { if (j == 1) cout << "@"; else cout << "."; } } for (int j = 1;j <= n + 1;j++) cout << "."; for (int j = 1;j <= 2 * n + 3;j++) { if (i == 2 * n + 3) cout << "@"; else { if (j == 1) cout << "@"; else cout << "."; } } for (int j = 1;j <= n + 1;j++) cout << "."; for (int j = 1;j <= 2 * n + 3;j++) { if (i == 1 || i == n + 2 || i == 2 * n + 3) cout << "@"; else if (1 < i && i < n + 2) { if (j == 1) cout << "@"; else cout << "."; } else if (n + 2 < i && i < 2 * n + 3) { if (j == 2 * n + 3) cout << "@"; else cout << "."; } } for (int j = 1;j <= n + 1;j++) cout << "."; cout << "*"; cout << '\n'; } for (int i = 1;i <= n;i++) { cout << "*"; for (int j = 2;j <= 13 * n + 18;j++) cout << "."; cout << "*"; cout << '\n'; } for (int i = 1;i <= 13 * n + 19;i++) cout << '*'; cout << '\n'; return 0; }
J
题解
知识点:思维,数学。
A不能变,B只有A-B与B两个值,于是C的变换方法只有形如交替的A-B与B,而最终C的符号取决于偶数次变换还是奇数次。公式为:
这里的 取负时的意义简单理解是交换了变换顺序,比如 。只要找到整数 满足等式即可,注意 时需要特判。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; bool solve() { int a, b, c, x; cin >> a >> b >> c >> x; if (2 * b - a == 0) { if (x - c == 0 || x + c - b == 0) cout << "Yes" << '\n'; else return false; } else if ((x - c) % (2 * b - a) == 0 || (x + c - b) % (a - 2 * b) == 0) cout << "Yes" << '\n'; else return false; return true; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--) { if (!solve()) cout << "No" << '\n'; } return 0; }
M
题解
知识点:线性dp,博弈论。
通过转移局面情况到起点,然后判断起点是否到达目标状态。
其中由于走法是固定向下或者向右,所以可以通过横纵坐标之和的奇偶性来决定当前是谁的回合。
对于A而言,两种走法有一种能得到目标状态就转移;对于B而言,两种走法有一种得不到目标状态就转移。
具体看代码注释qwq。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; char dt[507][507]; int dp[507][507]; ///三种局面是可以独立考虑的,分别看作能否一定走到A、B、(n,m)处状态 ///用三位二进制分别表示(i, j)处A是否一定能走到A、B、(n, m)处状态 ///1表示一定能走到,0表示不一定能走到(包括一定不) ///已知A处001,终点处为010,B处100 bool solve() { int n, m; cin >> n >> m; for (int i = 1;i <= n;i++) for (int j = 1;j <= m;j++) cin >> dt[i][j]; for (int i = n;i >= 1;i--) { for (int j = m;j >= 1;j--) { if (dt[i][j] == 'A') { dp[i][j] = 1;continue; } if (dt[i][j] == 'B') { dp[i][j] = 4;continue; } if (i == n && j == m) { dp[i][j] = 2;continue; } if (i == n) dp[i][j] = dp[i][j + 1]; else if (j == m) dp[i][j] = dp[i + 1][j];///无路可走的两种直接传递 else if ((i + j) & 1) dp[i][j] = dp[i + 1][j] & dp[i][j + 1];///可以通过坐标之和奇偶性得知是谁的回合,因为只能往下或者往右走,每轮都只会加一 else dp[i][j] = dp[i + 1][j] | dp[i][j + 1];///每种局面有0则B一定走0,有1则A一定走1 } } if (dp[1][1] & 1) cout << "yes" << ' '; else cout << "no" << ' '; if (dp[1][1] & 2) cout << "yes" << ' '; else cout << "no" << ' '; if (dp[1][1] & 4) cout << "yes" << ' '; else cout << "no" << ' '; cout << '\n'; return true; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--) { if (!solve()) cout << -1 << '\n'; } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16560477.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧