CF620D Professor GukiZ and Two Arrays Solution

这是一道有一点费脑子的简单题

题目链接(洛谷)
CodeForces

题意

给出两个长度为 n n n的数列 a a a, b b b,求任意交换两个数列中相同位置的数后(至多两次), ∣ S u m a − S u m b ∣ |{Sum_a-Sum_b}| SumaSumb的最小值

思路

因为这个交换次数很少,只有 2 2 2,以及这个 n n n的值同样很小,只有 2000 2000 2000,所以我们将这个问题拆开来看:

1 。 1^。 1考虑不交换,直接输入的时候累加一个 s u m a suma suma s u m b sumb sumb,然后做一个减法, f a b s fabs fabs一下即可。

2 。 2^。 2考虑只交换一次的情况,我们直接 n 2 n^2 n2暴力枚举 a i a_i ai b j b_j bj即可。

3 。 3^。 3考虑交换两次的情况,我们可以用 n 2 n^2 n2的暴力枚举出来在 a a a数组中任取两位所有的值, b b b数组同理,然后再用一个双指针更新答案即可。

代码

具体实现见代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <vector>
namespace OI
{
    #define pk putchar(' ')
    #define ph puts("")
    #define fi first
    #define se second
    template<class T>
    T Fabs(T x)
    {
        return x < 0 ? -x : x;
    }
    template<class T>
    void rd(T &x)
    {
        x = 0;
        int f = 1;
        char c;
        while (!isdigit(c = getchar())) if (c == '-') f = -1;
        do
        {
            x = (x << 3) + (x << 1) + (c ^ 48);
        } while (isdigit(c = getchar()));
        x *= f;
    }
    template<class T>
    void pt(T x)
    {
        if (x < 0)
            putchar('-'), x = -x;
        if (x > 9)
            pt(x / 10);
        putchar(x % 10 ^ 48);
    }
}
using namespace OI;
using namespace std;
typedef long long ll;
const int N = 2005;
int n, m, a[N], b[N], kind;
ll sa, sb;
vector<pair<int, pair<int, int> > > suma, sumb;
pair<int, int> ans[2];
int main()
{
    rd(n);
    for (int i = 1; i <= n; i++)
        rd(a[i]), sa += a[i];
    rd(m);
    for (int i = 1; i <= m; i++)
        rd(b[i]), sb += b[i];
    for (int i = 1; i < n; i++)
        for (int j = i + 1; j <= n; j++)
            suma.push_back({a[i] + a[j], {i, j}});
    for (int i = 1; i < m; i++)
        for (int j = i + 1; j <= m; j++)
            sumb.push_back({b[i] + b[j], {i, j}});
    sort(suma.begin(), suma.end());
    sort(sumb.begin(), sumb.end());
    ll minx = Fabs(sa - sb);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            ll tmp = Fabs(sa - sb + 2ll * b[j] - 2ll * a[i]);
            if (tmp < minx)
            {
                minx = tmp;
                kind = 1;
                ans[0] = {i, j};
            }
        }
    for (int i = 0, j = 0; i < (int)suma.size() && j < (int)sumb.size();)
    {
        ll tmp = (sa - sb + 2ll * sumb[j].fi - 2ll * suma[i].fi);
        if (Fabs(tmp) < minx)
        {
            minx = Fabs(tmp);
            kind = 2;
            ans[0] = {suma[i].se.fi, sumb[j].se.fi};
            ans[1] = {suma[i].se.se, sumb[j].se.se};
        }
        if (tmp > 0)
            i++;
        else
            j++;
    }
    pt(minx), ph, pt(kind), ph;
    for (int i = 0; i < kind; i++)
        pt(ans[i].fi), pk, pt(ans[i].se), ph;
    return 0;
}
谢谢
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值