专栏文章
题解:CF2156C Maximum GCD on Whiteboard
CF2156C题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min8z98e
- 此快照首次捕获于
- 2025/12/01 22:31 3 个月前
- 此快照最后确认于
- 2025/12/01 22:31 3 个月前
这题就很数学了,很练思维。
首先当一个数是 的倍数时,它不需要做任何操作,这是显然的。
然后给出一些结论:
- 我们完全可以先删除数再分裂数,答案不会更劣。
- 设我们要使所有数都是 的倍数,对于一个数 它如果 ,那它一定可以通过分裂来使得分成的两个数都是 的倍数。
- 如果 ,并且 不是 的倍数,那么 一定没有办法通过分裂来使得分成的两个数都是 的倍数,所以只能删除。
然后来证明:
- 采用反证法,假设有一个最优解,对于某个数 ,它将 分成了 ,然后删除了 或 ,那么我们完全可以先删掉 ,然后就不会有分裂操作,这样的话这个序列相当于少了一个数( 或 ),对于这道题,少了一个数只可能更优或相等,但不会更劣。
- 我们完全可以将 拆成 ,然后很显然满足 ,并且 和 显然都是 的倍数。
- 使用数学归纳法,设 表示这个命题对于 的真假,那么 肯定成立,因为 无法分割,那么考虑 ,并且 ,当然 ,因为如果 或者 ,那 自然成立(前面已经证明),没意义。假设我们将 分成 ,并且 ,那根据前面说的, 和 都是无法分割使得分成的两个数都是 的倍数,所以想要证反,只有可能 和 都是 的倍数,如果 ,则 ,那么 ,显然和 矛盾,因此,唯一的可能是 。假设 ,那么根据 得出 ,那么 ,与 不是 的倍数矛盾。最后就是 ,于是 ,与 矛盾。
证明完后, 你会发现,对于一个 ,它可行当且仅当:
然后你会发现可以用一个桶来记录每个数出现次数,那么就解决了第 个式子,然后第 个也就是加一个前缀和就行了。
所以说遍历 ,然后逐个判断是否可行即可。
代码:
CPP#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int a[N];
int pre[N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int _;
cin >> _;
while(_--)
{
int n,k;
cin >> n >> k;
for(int i = 1;i<=n;++i)
{
a[i] = 0;
}
for(int i = 1;i<=n;++i)
{
int x;
cin >> x;
++a[x];
}
for(int i = 1;i<=n;++i)
{
pre[i] = pre[i-1]+a[i];
}
int ans;
for(int i = 1;i<=n;++i)
{
if(n-pre[min(n,(i<<2)-1)]+a[i]+((i<<1)>n?0:a[i<<1])+(i*3>n?0:a[i*3])>=n-k)
{
ans = i;
}
}
cout << ans << '\n';
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...