C. Maximum GCD on Whiteboard
。。。长时间不做题真的会变笨
C. Maximum GCD on Whiteboard
https://codeforces.com/contest/2156/problem/C
题目大意:
给你n个数,让你求得这n个数的最大公约数,但是你可以通过对这n个数进行一些操作来变大这n个数原来的最大公约数,操作一:删除某一个数,但只能删k次;操作二:将一个数拆成三个数,x1,x2,x3,但是得保证1<=x1<=x2<=x3,且拆完之后只保留x1,x3。
题目思路:
贪心的想删除会占用k的次数,所以优先拆数,实在拆不了了再删数;
那么我们开始考虑拆数这个操作
首先我们需要枚举每个公约数,假设当前枚举到的公约数是g,那个这n个数中只要>4*g的数都可以通过拆数这个操作使得这个数所拆得的两个数都能被g整除
我们接下来来证明一下
首先x1就固定拆成g,此时x2+x3>=2g,为了方便理解我们可以写成,x2+x3>=m*g+p(m是>=2的整数,p可以为0,且p一定小于g),此时我们就可以把,x3拆分成(m-1)*g,x2拆分成g+p,这样就可以保证“这n个数中只要>4*g的数都可以通过拆数这个操作使得这个数所拆得的两个数都能被g整除”
证明结束
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5;
void solve() {int n,k;cin >> n >> k;vector<int>a(n+1),s(n+1);for (int i = 1; i <= n; i++) {int t;cin >> t;a[t]++;}for (int i = 1; i <= n; i++) {s[i] = s[i - 1] + a[i];}int ans=0;for (int i = 1; i <= n; i++) {int cnt=0;if (4*i<=n)cnt+=n-s[4*i-1];if(i<=n)cnt+=a[i];if (2*i<=n)cnt+=a[2*i];if (3*i<=n)cnt+=a[3*i];if (n-cnt<=k)ans=i;}cout << ans << endl;
}
signed main() {int q=1;cin >> q;while (q--) {solve();}
}
