1500A - Going Home

题意: 给一个数组,问是否存在四个不相同的下标xywz使得 a x + a y = a z + a w a_x+a_y = a_z+a_w ax+ay=az+aw,输出任意一组xyzw就可以。

因为 a x a_x ax的范围是2.5e6,所以sum的范围是5e6,

  • 看到网上很多说直接暴力然后对于每个和sum( s u m = a i + a j sum=a_i+a_j sum=ai+aj)存一下上一次达到sum的两个下标x,y,判断这ijxy是否构成一组解。不知道怎么证明正确性*

当有四组下标的和都为sum的时候,可以证明一定有解:(共8个下标

当有四个相同的下标,剩下四个下标构成一组解

当有三个相同的下标,剩下一组和这三组中任意一组构成一组解

当有两个相同的下标,剩下两组构成一组解

当没有相同的下标,输出任意两组

可以见代码(…

暴力枚举下标ij求他们的sum,复杂度上限是 O ( m i n ( 5 e 6 ∗ 3 + 1 , n 2 ) ) O(min(5e6*3+1, n^2)) O(min(5e63+1,n2)), 1e7

前面的加了和是sum的达到4必定有解的判断,后面的只有是和前一种相同sum的比较四个下标是否都不相同(不知道为什么后面这种也能证明一定正确(》》

在这里插入图片描述

好像还可以用set做,相同的数达到两对就直接有解,所以可以转化为都不相同的情况

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>

using namespace std;

const int N = 2e5 + 10;
const int M = 5e6 + 10;

int a[N];

struct node {
    int x, y;
};
vector<node> sum[M];

inline bool check(int x, int y, int z, int w) {
    if (x != z && x != w && y != z && y != w) return 1;
    return 0;
}

inline void getAns(int tot) {

    cout << "YES\n";

    map<int, int> mp;
    for (int i = 0; i < 4; ++i) {
        mp[sum[tot][i].x]++;
        mp[sum[tot][i].y]++;
    }

    int op = -1, pos = -1;
    for (auto x : mp) {
        if (x.second > op) {
            op = max(op, x.second);
            pos = x.first;
        }
    }

    if (op == 1) {
        cout << sum[tot][0].x << " " << sum[tot][0].y << " "
             << sum[tot][1].x << " " << sum[tot][1].y << endl;
        return;
    }
    if (op == 2) {
        int cnt = 0;
        for (int k = 0; k < 4; ++k) {
            if (cnt >= 2) break;
            if (sum[tot][k].x == pos || sum[tot][k].y == pos) continue;
            cnt++;
            cout << sum[tot][k].x << " " << sum[tot][k].y << " ";
        }
    }
    if (op == 3) {
        bool f = 0;
        for (int k = 0; k < 4; ++k) {
            if (sum[tot][k].x == pos && f || sum[tot][k].y == pos && f) continue;
            if (sum[tot][k].x == pos || sum[tot][k].y == pos) f = 1;
            cout << sum[tot][k].x << " " << sum[tot][k].y << " ";
        }
    }
    if (op == 4) {
        for (int k = 0; k < 4; ++k) {
            if (sum[tot][k].x == pos) cout << sum[tot][k].y << " ";
            else cout << sum[tot][k].x << " ";
        }
    }

}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }

//    sort(a + 1, a + n + 1, [](int x, int y) { return x < y; });

    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            int tot = a[i] + a[j];

            sum[tot].push_back({i, j});
            int siz = sum[tot].size();

            if (siz >= 4) {
                getAns(tot);
                return 0;
            }
            if (siz > 1 && check(i, j, sum[tot][siz - 2].x, sum[tot][siz - 2].y)) {
                cout << "YES\n";
                cout << i << " " << j << " " << sum[tot][siz - 2].x << " " << sum[tot][siz - 2].y << endl;
                return 0;
            }

        }
    }

    cout << "NO\n";

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值