最大值的最小可能,可以用二分答案解决,但是题目有m次输出,直接二分答案时间复杂度为,肯定会超时。
所以我们可以先预处理出来如果还留在学校的人数最多的班级的最少的可能人数为时,需要走的人数是多少。
第一种方法:我们可以用差分的方法求出数组,表示人数大于等于的班级数量。再对数组求一次前缀和,表示还留在学校的人数最多的班级的最少数量为时,学校中剩下的总人数为。
实现代码:
for (int i = 1; i <= n; i++) {
int x; cin >> x;
A[x]++;
}
for(int i = 1; i <= m; i ++)
{
if(A[i]) B[1] ++, B[A[i] + 1] --; //求差分数组
}
//求人数大于等于i的班级数量
for(int i = 1; i <= n; i ++)B[i] += B[i - 1];
//还留在学校的人数最多的班级的最少数量为时,学校中剩下的总人数
for(int i = 1; i <= n; i ++)B[i] += B[i - 1];
然后我们去二分可能的答案,对于每一个mid,应该走的学生数量()为。如果,说明我们多算了一部分拖堂的人数,这种情况需要将。得到的如果大于,说明的值太小了,右移;否则说明的值太大了,左移。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
int A[N], B[N];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int n, m, k;
cin >> n >> m >> k;
int sum = n;
int mx = 0;
for (int i = 1; i <= n; i++) {
int x; cin >> x;
A[x]++;
}
for(int i = 1; i <= m; i ++)
{
if(A[i]) B[1] ++, B[A[i] + 1] --;
}
for(int i = 1; i <= n; i ++)B[i] += B[i - 1];
for(int i = 1; i <= n; i ++)B[i] += B[i - 1];
for (int i = 1; i <= m; i++){
if (sum - A[i] < k) {
cout << "-1 ";
continue;
}
int l = 0, r = n;
while (l < r){
int mid = l + r >> 1;
ll res = n - B[mid];
if (A[i] > mid) res -= (A[i] - mid);
if (res <= k) r = mid;
else l = mid + 1;
}
cout << l << ' ';
}
return 0;
}
第二种解法:我们可以用后缀和求出如果还留在学校的人数最多的班级的最少的可能人数为时,需要走的人数是多少。(第一次了解到这种解法,还不太理解)
实现代码:
for (int i = 1; i <= n; i++) {
int x; cin >> x;
A[x]++;
}
for (int i = 1; i <= m; i++){
if (A[i]) B[A[i] - 1]++;
}
for (int i = n; i >= 0; i--) B[i] += B[i + 1];
//直接求出如果还留在学校的人数最多的班级的最少的可能人数为i时,需要走的人数是多少
for (int i = n; i >= 0; i--) B[i] += B[i + 1];
然后我们去二分可能的答案,对于每一个mid,应该走的学生数量()为。如果,说明我们多算了一部分拖堂的人数,这种情况需要将。得到的如果大于,说明的值太小了,右移;否则说明的值太大了,左移。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
ll A[N], B[N];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int n, m, k;
cin >> n >> m >> k;
int sum = n;
int mx = 0;
for (int i = 1; i <= n; i++) {
int x; cin >> x;
A[x]++;
}
for (int i = 1; i <= m; i++){
if (A[i]) B[A[i] - 1]++;
}
for (int i = n; i >= 0; i--) B[i] += B[i + 1];
for (int i = n; i >= 0; i--) B[i] += B[i + 1];
for (int i = 1; i <= m; i++){
if (sum - A[i] < k) {
cout << "-1 ";
continue;
}
int l = 0, r = n;
while (l < r){
int mid = l + r >> 1;
ll res = B[mid];
if (A[i] > mid) res -= (A[i] - mid);
if (res <= k) r = mid;
else l = mid + 1;
}
cout << l << ' ';
}
return 0;
}