Codeforces 798D 二维贪心找可行解

传送门:题目

题意:

给两个序列A,B然后找你找到一个下标集合PP的个数 P.sizen2+1 P . s i z e ≤ ⌊ n 2 ⌋ + 1 ,然后以P为下标的AB集合记作 A2B2 A 2 B 2 ,满足 2Sum(A2)>Sum(A) 2 ∗ S u m ( A 2 ) > S u m ( A ) 2Sum(B2)>Sum(B) 2 ∗ S u m ( B 2 ) > S u m ( B )
题目保证解一定存在。

题解:

首先,基于贪心的策略,我们让 P.size=n2+1 P . s i z e = ⌊ n 2 ⌋ + 1 ,人多力量大么,不等式的左边个数多,就越容易大于右边的(贪心)。
然后,我们发现这是个二维贪心,必须AB同时满足。
最后也是最重要的,题目要求的是可行解,而不是最优解。做题的时候没想到这点,一直想如何让不等式的左面最大。其实这是不必要的,只要满足不等式就行。

降维:

我们先想一维贪心。
如果是最优解:直接把序列从大到小排,然后取前 P.size P . s i z e 个就是最大的,很简单。
如果是可行解:
从左到右,两两组成一对(先不考虑奇数和偶数的问题,实时上等你明白贪心的规律,你就会发现题目中 P.size P . s i z e 中加1就是为了方便奇数情况),比如说:
A=[8,7,4,8] A = [ 8 , 7 , 4 , 8 ] ,第一对87,找到最大的8,第二对48,找到最大的8,分别找到他们的索引值14,组成P集合,这样一定是可行解。
为什么?仔细看不等式的左面,系数2保证所有值计算时都会成以2倍,我们在选取的时候每次保证在每两个之中选择一个较大的,那么现在我们把数组分成了两堆, DuiDui D u i 大 和 D u i 小 。那么不难知道 2Dui>Dui+Dui 2 ∗ D u i 大 > D u i 大 + D u i 小

升维+贪心+可行解:

我们知道的一维状况下的最优解和一维状况下的可行解。
我们现在可以把A序列先从大到小排个序,然后从左往右扫A序列的索引值,然后把这些索引值放到B序列中,然后把B序列两两组对,找最大值,相当于一维贪心找可行解了。
因为A排过序了,我们可以肯定,取A中的,一定都是较大的,然后按照一维的思路,我们找B的可行解,这样我们保证AB都是可行解了,注意,这里A不是最优解。(说的有点乱,可以看代码,比较清楚)。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100010;
pair<int, int> a[maxn];
int b[maxn],n;
bool cmp(pair<int, int> lhs, pair<int, int> rhs) {
    return lhs.first > rhs.first;
}
int main(void){
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i].first, a[i].second = i;
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    sort(a + 1, a + 1 + n, cmp);
    cout << n / 2 + 1 << "\n" << a[1].second << " ";
    for (int i = 2; i <= n; i += 2)
        cout << (b[a[i].second] > b[a[i + 1].second] ? a[i].second : a[i + 1].second) << " \n"[i==n||i==n-1];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值