CF1593D2 Half of Same

题目大意:

给定一个包含 \(n\)\(n\) 是偶数)个整数的数列 \(a_1,a_2,\ldots,a_n\)
考虑一个可能的正整数 \(k\),在每次操作中,你可以选定一个 \(i\),并将 \(a_i\) 减少 \(k\)
你可以执行任意多次(也可能是零次)操作,使这个数列中至少一半的数相等。
请找出最大的符合条件的 \(k\),如果 \(k\) 可以是任意的大小,输出 \(-1\)

观察题目,不难发现,满足输出 \(-1\) 的充要条件就是原数列里已经至少有一半的数相等了,因此输入后我们判断一下这种情况是否存在即可。
题目中的操作,实际上就等价于让我们寻找一个最大的 \(k\),使得数列中至少有一半的数关于它同余即可。我们在数列中选出 \(a\)\(b\),使得如下式子成立:

\[a\equiv b(\mod k) \]

以此推出,得:

\[k\mid (a-b) \]

这就说明,我们只需要枚举数列中任意两个数,将他们相减后得到的数设为 \(d\),枚举 \(d\) 的因数,寻找一个最大的因数使得数列中有至少一半的数关于它同余即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10000000;
int n,a[MAXN];
int t;
map<int,int> m;
int gcd(int a,int b){
   if(!b){
   	return a;
   }
   return gcd(b,a % b);
}
int main(){
   cin >> t;
   while(t--){
   	m.clear();
   	cin >> n;
   	n /= 2;
   	for(int i = 1; i <= 2 * n; i++){
   		cin >> a[i];
   		m[a[i]]++;
   	}
   	bool flagb = 0;
   	for(int i = 1; i <= 2 * n; i++){
   		if(m[a[i]] >= n){
   			cout << "-1\n";
   			flagb = 1;
   			break;
   		}
   	}
   	if(flagb)continue;
   	bool flag;
   	int ans = 0;
   	for(int l = 1; l <= 2 * n; l++){
   		//cout << 1 << "\n";
   		for(int r = l + 1; r <= 2 * n; r++){
   			for(int j = (int)(sqrt(abs(a[l] - a[r]))) + 1; j >= 1; j--){
   				if(abs(a[l] - a[r]) % j == 0 && abs(a[l] - a[r]) != 0){
   					flag = 1;
   					int cnt = 0;
   					for(int i = 1; i <= 2 * n; i++){
   						if((a[i] + MAXN) % j == (a[l] + MAXN) % j)cnt++;
   						if(cnt == n){
   							ans = max(ans,j);
   							break;
   						}
   					}
   					cnt = 0;
   					int h = abs(a[l] - a[r]) / j;
   					for(int i = 1; i <= 2 * n; i++){
   						if((a[i] + MAXN) % h == (a[l] + MAXN) % h)cnt++;
   						if(cnt == n){
   							ans = max(ans,h);
   							break;
   						}
   					}
   				}
   				
   			}
   		}
   	}
   	cout << ans << "\n";
   }
   
   return 0;
}
posted @ 2022-07-21 10:01  腾云今天首飞了吗  阅读(23)  评论(0编辑  收藏  举报