题目概述

原题参考:B. Make Almost Equal With Mod
给出一个长度为n的数组,可以证明的是,一定存在一个整数k使得a[i]=a[i]%k之后,数组a中只有两个数,请给出整数k,当然,若有多个k,随意给出一个即可

思路想法

太巧妙了,本来以为是暴力可以过的,因为其实数组a的很小,最多100个数,当时猜的是对于任意的数,都会存在一个很小的k满足,就可以直接暴力跑过,但是事实上是错误的,还是tle了,因为ai的取值很大,最大是1e18,这里就不得不提到这个问题的解法了
就向题目说的,本题解法与二进制相关,想一下取模运算的几个例子,123%100=23,1245%1000=245...以这种十进制的取模运算很容易看出来一种截断效应,当然当k!=10^i次方时是不存在该种现象的,随便举几个二进制的例子,1011%10=1,1001111%100=11,因此二进制取模对2的幂次放也存在截断效应,这时候我们在判断一下二进制每一位数有几种可能,每一位只有两种可能,当当前位相同时,看下一位,如果不同,那么这一位之后的都想同,这一位不同,正是两个数,否则如果这一位也相同,那么继续往下

参考代码

#include <bits/stdc++.h>
using namespace std;
#define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define pll pair<long long, long long>
#define pii pair<int, int>
#define vi vector<int>
#define vl vector<long long>
#define ll long long
#define ull unsigned long long
const ll INF = 9187201950435737471;
const int inf = 2139062143;
const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int N = 107;
ll n, a[N];
void solve() {
	cin >> n; 
	for(int i=1; i<=n; i++) cin >> a[i];
	set<ll> st;
	ll k = 2;
	while(true) {
		int i;
		for(i=1; i<=n; i++) {
			st.insert(a[i]%k);
			if(st.size() > 2) break;
		}
		if(i == n+1 && st.size() == 2) break;
		else k <<= 1, st.clear();
	}
	cout << k << endl;
	st.clear();
}
int main() {
#ifdef xrl
	freopen("in.txt", "r", stdin), freopen("out.txt", "w", stdout);
#endif
	FAST_IO;
	int t = 1;
	cin >> t;
	while(t --) solve();
#ifdef xrl
	cout << "Time used = " << (double)(clock() * 1.0 / CLOCKS_PER_SEC) << "s";
#endif
	return 0;
}

做题反思

太巧妙了,实在是太好玩了,所以对于任意数组,其实可以通过取模运算变为一个或者两个数

posted on 2024-03-02 00:26  山余木  阅读(19)  评论(0)    收藏  举报