<988D>
题意:
给定若干个数,问在其中挑选几个数组成一个集合,使得集合中任意以两个数a, b(a > b)的差值均为2^n。
思路:
这题要先找规律,这个规律就是,集合中的元素最多有3个,证明如下:
假设集合内目前只有三个元素:x,y,z 且 x < y < z
则根据题意,有如下关系:
z - y = 2^a (1)
y - x = 2^b (2)
z - x = 2^c (3)
所以由 (1)式 + (2)式,再与 (3)式联立,得 z - x = 2^a + 2^b = 2^c,由此可得,当且仅当
2^c = 2 * 2^b = 2 * 2^a 时上述等式成立,即 a = b = c - 1;
所以由 a = b, 得 2^a = 2^b,即 z - y = y - x,所以 x,y,z构成等差数列,
由上可知,当集合中有四个元素的时候,x < y < z < k 时,显然就不成立了,因为你要满足从中挑出的任意三个元素满足等差数列,比如 <x, y, k> 或 <x, z, k>时就不成立了,因为x, y, z, k满足等差数列,且公差不能为0,所以它的三元组子集就未必满足构成等差这个条件了。
找到这个规律以后就好办了,存进集合set中,然后在1~2e9中枚举2^n,再加到集合元素a[i]上,看有几个在集合中即可,如果够不成等差数列,即只有一个元素的时候,那就输出a[1]就好了。
本人AC代码:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
map <int, int> mp;
vector <int> vec;
queue <int> qua;
set <ll> sst;
int n;
ll a[maxn];
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
sst.insert(a[i]);
}
for(int i = 1; i <= n; i++) {
for(ll j = 1; j <= 2e9; j *= 2) {
if(sst.count(a[i] + j) && sst.count(a[i] + 2 * j)) {
puts("3");
printf("%I64d %I64d %I64d\n", a[i], a[i] + j, a[i] + 2 * j);
return 0;
}
}
}
for(int i = 1; i <= n; i++) {
for(ll j = 1; j <= 2e9; j *= 2) {
if(sst.count(a[i] + j)) {
puts("2");
printf("%I64d %I64d\n", a[i], a[i] + j);
return 0;
}
}
}
puts("1");
cout << a[1] << endl;
}