题目描述
【问题描述】
在一个班级中,恰好有
n
n
n名男生和
n
n
n名女生。为了便于管理,老师给这
n
n
n名男生和
n
n
n名女生分别从
1
1
1到
n
n
n进行编号。某一天,老师在班级里开展了一项游戏。这个游戏需要将班级里的同学分成若干个不同的小组,且每个小组中需要同等数量的男生和女生。每个小组中,每一名男生需要和一名同小组的女生进行配对搭档,来完成游戏中的任务。一名男生不能和多名女生进行配对,一名女生也不能和多名男生进行配对。老师决定采用一种比较简便的方式对全班同学进行分组:按编号顺序进行划分。具体来说,老师会确定若干个区间
[
l
1
,
r
1
]
,
[
l
2
,
r
2
]
⋯
[
l
k
,
r
k
]
[l_1,r_1],[l_2,r_2] \cdots [l_k, r_k]
[l1,r1],[l2,r2]⋯[lk,rk],满足
l
1
=
1
,
r
k
=
n
,
l
i
=
r
i
−
1
+
1
(
1
<
i
≤
k
)
l_1 = 1,r_k=n,l_i=r_{i-1}+1(1<i \leq k)
l1=1,rk=n,li=ri−1+1(1<i≤k)编号处于同一个区间的男生和女生分为一组。
为了让游戏保证尽量公平,老师希望没有哪一个小组的实力过于突出。具体来说,每名同学都有一个正整数实力值,用来衡量一名同学的能力大小。当一名实力值为
a
a
a和一名实力值
b
b
b的女生进行配对时,这一对同学的实力值就会是
a
∗
b
a * b
a∗b。而一个小组的综合实力就是这个小组中每一对同学的实力值的和。为了保证不出现综合实力过高的小组,老师希望在分组后,不论小组内如何配对,每个小组的综合实力都不会超过一个给定值
M
M
M。
最后,为了缩短游戏进行的时间,老师希望所分的小组数量尽可能少。你需要帮助他求出:在满足上述分组规则的情况下,最少的小组数量是多少?
【输入文件】
输入文件第一行为两个正整数
n
,
m
n,m
n,m。
接下来两行,第一行为
n
n
n个正整数
a
1
,
a
2
,
⋯
,
a
n
a_1,a_2,\cdots,a_n
a1,a2,⋯,an其中
a
i
a_i
ai表示编号为
i
i
i的男生的实力第二行为
n
n
n个正整数
b
1
,
b
2
,
⋯
,
b
n
b_1,b_2,\cdots,b_n
b1,b2,⋯,bn,其中
b
i
b_i
bi表示编号为
i
i
i的女生的实力值。
【输出文件】
输出一个整数,为最少的小组数量。输入数据保证至少存在一种满足分组
规则的分组方式。
【输入输出样例】
pair.in
3 50
6 7 2
6 3 5
pqir.out
2
题解
-
对于每个小组来说能够得到最大综合实力的方式为:最大男生和最大的女生配对,次大的和次大的配对,以此类推。
-
然后我们发现:在小组内新加入一对,那么小组最大综合能力一定上升
显然 -
根据贪心的思想,从编号为 1 1 1的开始向后考虑,尽可能的把人放在同一组,直到超过 m m m,再分下一组即可。
-
那我们思考有没有什么方便的方法求最大综合实力的方式。
倍增+二分!!对于每一组,考虑这组大小为 1 , 2 , 4 , ⋯ , 2 p 1,2,4,\cdots, 2^p 1,2,4,⋯,2p时,最大综合实力值都没有超过 m m m,但组大小为 2 p + 1 2^{p+1} 2p+1,时最大综合实力值会超过 m m m,那么这组的最大大小应该在 [ 2 p , 2 p + 1 − 1 ] [2^p,2^{p+1}-1] [2p,2p+1−1]内。在此范围内进行二分即可。这样,当实际组大小是 k k k时,时间复杂度应为 O ( k l o g 2 k ) O(klog^2k) O(klog2k)。则总时间复杂度不超过 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
typedef long long LL;
template <class T>
inline void read(T &s) {
s = 0; T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int n;
LL m;
LL a[maxn], b[maxn];
LL c[maxn], d[maxn];
bool check(int l, int len) {
int r = l + len - 1, tot = 0;
for (int i = l; i <= r; ++i)
c[++tot] = a[i], d[tot] = b[i];
LL ret = 0ll;
sort(c + 1, c + tot + 1);
sort(d + 1, d + tot + 1);
for (int i = 1; i <= tot; ++i) {
ret += c[i] * d[i];
if (ret > m) return false;
}
return true;
}
int solve() {
int L = 1, R = n, cnt = 0;
while (L <= R) {
int len = 1;
for (; check(L, len) && L + len - 1 <= R; len <<= 1);
int l = len >> 1, r = len - 1;
while (l < r) {
int mid = (l + r + 1) >> 1;
if (check(L, mid)) l = mid;
else r = mid - 1;
}
L += l; cnt++;
}
return cnt;
}
#define FILE "pair"
int main() {
freopen(FILE".in", "r", stdin); freopen(FILE".out", "w", stdout);
read(n); read(m);
for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 1; i <= n; ++i) read(b[i]);
printf("%d\n", solve());
return 0;
}