专栏文章
AT ARC200D |A + A|
AT_arc200_d题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio8khag
- 此快照首次捕获于
- 2025/12/02 15:07 3 个月前
- 此快照最后确认于
- 2025/12/02 15:07 3 个月前
首先让 特殊一点,考虑到若让 的元素都减掉一个值,那么和的数量是不变的,于是减掉 ,就可以强制要求 。
接下来进行一些尝试,发现 ,于是构造 , 共 个数就可以被凑出了。
那么 为奇数就已经被解决了,此时只需要考虑偶数的情况了。
上面的构造看起来比较优美,于是考虑从这个基础上调整 个值来达成目标。
毕竟刚刚的选取都是正着选的,为什么不能倒着选呢?
考虑到 ,于是选上 这些相当于是把 向左平移了 位并加入了一个 的值。
考虑到 ,于是选上 这些相当于是把 向左平移了 位并加入了一个 的值。
如果选取 发现好像没什么用。
不过如果选取 ,会发现当 时, 平移后能够得到 这 个值,且还会有 这个值,会发现这就实现了多 个数的操作,能够把奇数转为偶数了。
不过如果选取 ,会发现当 时, 平移后能够得到 这 个值,且还会有 这个值,会发现这就实现了多 个数的操作,能够把奇数转为偶数了。
接下来就是去分析使用的条件了,经过一定的分讨,或者可以自己代入一些值模拟,会知道 都是可行的,那么就只需要考虑剩下的边界情况了。
首先对于 的情况,全选上肯定可行。
接下来考虑 的情况,我们可以说明一定只会选出来 个数:
- 当选出 个数时,最多只有 种组合,必然凑不出 种,不合法。
- 当选出 个数 时, 必然不同,于是至少有 种和,不合法。
对于选出 个数 的情况,就只能要求 ,那就是当 时取 ,否则无解。
根据刚刚的经验,可以知道对于 时只可能选出 个数,尝试分讨:
- 当选出 个数 时, 本身不同,所以 中需要有 个值与 中的某个值相等,考虑继续分讨:
- ,当 时可以令 ,此时 不合法。
- ,当 时可以令 ( 也可以),此时 合法。
- (等式右边不能为 ,因为这会导出 ),若 会导出 ,若 会导出与第一次分讨相同的结果。
- 当选出 个数 时, 本身不同,所以 都必须和 中的某个值相等,于是分讨:
- ,当 时可以令 , 不合法。
- ,当 时有 的值, 不合法。
- 或 ,此时已经满足 ,故不继续讨论(能发现 也是一组合法解)。
经过刚刚的分讨,可以知道只有当 时满足条件,其中构造为 。
时间复杂度 。
CPP#include <bits/stdc++.h>
inline void solve() {
int m, k;
scanf("%d%d", &m, &k);
std::vector<int> ans;
if (k % 2 == 1) {
for (int i = 0; i <= (k - 1) / 2; i++) ans.push_back(i);
} else if (k == m) {
for (int i = 0; i < m; i++) ans.push_back(i);
} else if (k == 2) {
if (m % 2 != 0) {
return puts("No"), void();
} else {
ans = {0, m / 2};
}
} else if (k >= 6) {
for (int i = 0; i <= (k - 4) / 2; i++) ans.push_back(i);
ans.push_back(m - 2);
} else if (m % 4 == 0) {
ans = {0, m / 2, m / 4};
} else {
return puts("No"), void();
}
puts("Yes");
printf("%zu\n", ans.size());
for (int x : ans) printf("%d ", x);
puts("");
}
int main() {
int t; scanf("%d", &t);
while (t--) solve();
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...