传送门:题目
题意:
给两个序列A,B然后找你找到一个下标集合P,P的个数
P.size≤⌊n2⌋+1
P
.
s
i
z
e
≤
⌊
n
2
⌋
+
1
,然后以P为下标的AB集合记作
A2B2
A
2
B
2
,满足
2∗Sum(A2)>Sum(A)
2
∗
S
u
m
(
A
2
)
>
S
u
m
(
A
)
和
2∗Sum(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
]
,第一对8和7,找到最大的8,第二对4和8,找到最大的8,分别找到他们的索引值1和4,组成P集合,这样一定是可行解。
为什么?仔细看不等式的左面,系数2保证所有值计算时都会成以2倍,我们在选取的时候每次保证在每两个之中选择一个较大的,那么现在我们把数组分成了两堆,
Dui大和Dui小
D
u
i
大
和
D
u
i
小
。那么不难知道
2∗Dui大>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;
}