AcWing 4505. 最大子集

在这里插入图片描述

  • 假设集合内A<B<C<D,且差值分别为 2 x 2^x 2x, 2 y 2^y 2y, 2 z 2^z 2z,那么我们可以得到 2 x + 2 y = 2 k 2^x+2^y=2^k 2x+2y=2k,也就是 1 + 2 y − x = 2 k − x 1+2^{y-x}=2^{k-x} 1+2yx=2kx,除了1另外两个都只可能为1或者偶数,如果两个都是偶数就不成立了,因此, y = x y=x y=x,也就是说集合中任意两个连续的数的差值都是一样的(等差数列)都是 2 x 2^x 2x,这样的话A和D之间的差值就是 3 ∗ 2 x 3*2^x 32x,必然就不是一个2的整数幂,就不对了,因此,集合中如果包含大于等于4个数,必然出现矛盾
  • 我们要多次快速查找原序列中是否有某个元素,且原序列本身都不重复,因此我们用一个set来存入原序列
  • 注意这里如果用这种方式来写必须加上前两行开启O2优化
#pragma GCC optimize ("Ofast")
#pragma GCC optimize ("unroll-loops")
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <bitset>
#define endl '\n'
#define _(a) cout << #a << ": " << (a) << "    "
#define one first
#define two second
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<int, ll> pil;
const int N = 2e5 + 10;

int n;
int a[N];

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++ i) cin >> a[i];
    unordered_set<int> se(a + 1, a + n + 1);
    for (int i = 1; i <= n; ++ i) {
        for (int j = 0; j < 31; ++ j) {
            if (se.count(a[i] - (1 << j)) && se.count(a[i] + (1 << j))) {
                cout << 3 << endl;
                cout << a[i] - (1 << j) << ' ' << a[i] << ' ' << a[i] + (1 << j) << endl;
                return 0;
            }
        }
    }
    for (int i = 1; i <= n; ++ i) {
        for (int j = 0; j < 31; ++ j) {
            if (se.count(a[i] - (1 << j))) {
                cout << 2 << endl;
                cout << a[i] << ' ' << a[i] - (1 << j);
                return 0;
            }
        }
    }
    cout << 1 << endl << a[1];
}

  • 因为用unorderd_set(常数很大)也是会tle的,因此我们手写哈希表
  • 哈希表M一般是数据范围的2~3倍(下限),(由于数据范围空间足够(只有2e5)这里取十倍,)且为质数(质数是因为防止哈希碰撞 就是防止太多数取余以后相等)
  • 由于这里数值有 − 1 e 9 -1e9 1e9,可能是负数,因此给哈希表初始化就不初始化成-1,可以初始化成0x3f3f3f3f(大于1e9,且0x3f+0x3f也不超过int范围)
  • 哈希表不要忘了赋值
  • 哈希表可以节省三倍时间
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5 + 10, M = 1999997, inf = 0x3f3f3f3f;

int n;
int a[N], h[M];

int find(int x) {
    int t = (x % M + M) % M;
    while (h[t] != inf && h[t] != x) {
        if ( ++ t == M) {
            t = 0;
        }
    }
    return t;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++ i) cin >> a[i];
    sort(a + 1, a + 1 + n);
    memset(h, 0x3f, sizeof h);
    int res[4], s[4];
    int rt = 0, st = 0;
    for (int i = 1; i <= n; ++ i) {
        for (int j = 0; j < 31; ++ j) {
            int d = 1 << j;
            s[1] = a[i], st = 1;
            for (int k = 1; k <= 2; ++ k) {
                int now = a[i] - k * d;
                if (h[find(now)] == inf) break;
                s[ ++ st] = now;
            }
            if (rt < st) {
                rt = st;
                memcpy(res, s, sizeof s);
                if (rt == 3) break;
            }
        }
        if (rt == 3) break;
        h[find(a[i])] = a[i];
    }
    cout << rt << endl;
    for (int i = 1; i <= rt; ++ i) cout << res[i] << ' ';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值