题目链接:http://codeforces.com/contest/988/problem/D
题意:给n个互不相同的数,在里面选取一些数组成集合,满足集合内的数任意两两绝对值之差是2的幂,求这个集合能构成的最多元素个数并分别输出。
题解:可以证明这个集合最大是3。假设三个数a,b,c能构成这个集合(a < b < c),则有b - a = 2 ^ x,c - b = 2 ^ y,c - a = 2 ^ z,则2 ^ x + 2 ^ y = 2 ^ z
显然z > x并且z > y,不妨设x < y,两边同时除以2 ^ x,则 1 + 2^(y - x) = 2^(z - x),要使该等式成立,则y - x = 0,z - x = 1
即 x = y = z - 1,进一步的,a + c = 2 * b
假设存在4个数a,b,c,d(a < b < c < d)能构成该集合,依据上面的结论有 a + c = 2 * b,a + d = 2 * b,推出 c = d,矛盾,则结论成立。
知道了最多有三个,则可以枚举出现的集合大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<map>
#include<iostream>
using namespace std;
typedef long long ll;
map<ll,ll>arr;
const int maxn = 2e5 +5;
ll a[maxn];
ll s[34];
int main()
{
s[0] = 1;
for(int i = 0; i <= 30; i ++){
s[i + 1] = s[i] * 2;
}
int n;
cin>>n;
for(int i = 0; i < n; i ++){
cin>>a[i];
arr[a[i]] = 1;
}
int cnt = 0;
ll p1 = 0,p2 = 0, p3 = 0;
for(int i = 0; i < n; i ++){
for(int j = 0; j <= 31; j ++){
if(arr.find(a[i] + s[j])!= arr.end()){
if(((2 * a[i] + s[j])%2==0)&&arr.find((2 * a[i] + s[j])/2)!=arr.end()){
cout<<3<<endl;
cout<<a[i]<<" "<<a[i] + s[j]<<" "<<(2 * a[i]+s[j]) /2<<endl;
return 0;
}
else {
cnt = 2;
p1 = a[i];
p2 = a[i] + s[j];
}
}
}
}
if(cnt == 2){
cout<<2<<endl;
cout<<p1<<" "<<p2<<endl;
}
else{
cout<<1<<endl;
cout<<a[0]<<endl;
}
return 0;

}