【题解】放假回家

题目大意

第一行输入 \(n\) 代表有 \(n\) 个同学,\(m\) 代表卡车最多运的物品重量。

第二行输入 \(n\) 个数字 \(a_i\) 表示第 \(i\) 个同学的行李总量。

每组数据为 \(n\) 个子问题:一定将第 \(i\) 个同学的行李放进卡车,而卡车还会有剩余空间,放上第 \(1\)\(i - 1\) 同学的行李,尽量放更多同学的行李,问会有多少同学的行李不能放进卡车。

思路

我们由题意可以看出,每组数据输出的 \(n\) 个答案为独立的数据。但是,第 \(i\) 个问题会包括前面的所有学生,我可以以此将这 \(n\) 个问题联系到一起。

由于我们不知道放了 \(i\) 同学的行李之后,最多能放哪些同学的行李,通过贪心的思想,所以我们应该尽量放重量小的行李,保证等待的同学最少。

由于我们可以放的同学人数是不确定的,我们可以选择二分来获取人数,判断人数为 \(mid\) 时会不会超重。

但每次进行一次排序或优先队列都会超时。

我们可以选择将行李的重量排序,但是我们只能选取前 \(i - 1\) 个同学,但是排了序之后我们并不知道原本前 \(i - 1\) 的排序后的位置,如果我们暴力去找它们的排序后的位置,也一定会超时。

我们可以在二分之前,用 \(index\) 数组记录第 \(i\) 个同学的行李排序后的下标。

我们可以考虑建立两个树状数组 \(c1\)\(c2\) 分别维护人数的前缀和和行李重量的前缀和,将 \(i\) 号同学的信息分别放到 \(c1_{index_i}\)\(c2_{index_i}\)

所以我们二分的人数,就应该改为树状数组的下标,所以应该初始化 \(l = 1\), \(r = n\)

可以参考以下代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int MAXN = 1e5 + 5;
int T;
int n, m;
struct Node {
	int v, id;
	bool operator < (const Node o) const { return v < o.v; }
} a[MAXN];
int b[MAXN];
int ind[MAXN];
int c1[MAXN], c2[MAXN];
int lowbit(int x) { return (x & (-x)); }
void update(int* c, int x, int k) {
	while (x <= n) {
		c[x] += k;
		x += lowbit(x);
	}
}
int query(int* c, int x) {
	int res = 0;
	while (x > 0) {
		res += c[x];
		x -= lowbit(x);
	}
	return res;
}
bool check(int sum, int x) {
	return sum >= query(c2, x);
}
signed main() {
	scanf("%lld", &T);
	while (T--) {
		memset(c1, 0, sizeof(c1));
		memset(c2, 0, sizeof(c2));
		scanf("%lld %lld", &n, &m);
		for (int i = 1; i <= n; i++)
			scanf("%lld", &a[i].v), a[i].id = i, b[i] = a[i].v;
		sort(a + 1, a + n + 1);
		for (int i = 1; i <= n; i++)
			ind[a[i].id] = i;
		int ans = 0;
		for (int i = 1; i <= n; i++) {
			int l = 0, r = n, sum = m - b[i];
			while (l + 1 < r) {
				int mid = (l + r) >> 1;
				if (check(sum, mid))
					l = mid;
				else
					r = mid;
			}
			int p = check(sum, r) ? r : l;
			printf("%lld ", i - query(c1, p) - 1);
			update(c1, ind[i], 1), update(c2, ind[i], b[i]);
		}
		printf("\n");
	}
	return 0;
}
posted @ 2022-07-16 21:28  zhou_ziyi  阅读(40)  评论(0)    收藏  举报