C. Berland Regional

https://codeforces.com/problemset/problem/1519/C

题意:给定n个学生,每个学生属于一个学校,并且每个学生都有一个力量s。现在有个轮询k∈[1, n],每个学校会将最强的学生分为k组,这k组学生的力量总和代表了当前学校的总和,对于每个k,询问所有的力量总和是多少?学校排除的学生必须为k的整数倍。

思路:按学校来考虑,每个学校对于每个k,都可以计算出对答案的贡献。先对当前学校,按学生的力量从大到小排序,然后求前缀和。随后考虑每个k,对于每个k,计算出当前学校可以派出多少学生,时间复杂度是O(1),然后直接将这个力量值贡献到询问为k的答案中即可。 时间复杂度是:O(n) * O(m),其中m是所有学校中最大的学生数量。

总结:一开始没思路,想到了暴力的方法,但是感觉会TLE,后来想了想虽然最大的学生数量是O(n) * O(m),但是这个只表示最差的时间复杂度,因为学生的数量总数还是n,所以复杂度是达不到平方级别的,具体怎么考虑这个复杂度?
二次思考:假设所有的学生都在同一大学,那么时间复杂度就是O(n * log(n)),如果每个学校都有一个人,那么就是O(n),所以最坏的时间是O(n * log(n))

inline void solve(){
	int n;
	cin >> n;

	vector<int> a(n + 1);
	vector<vector<int>> b(n + 1);
	for (int i = 0; i < n; ++i) {
		int x;
		cin >> x;
		x--;
		b[x].push_back(i);
	}

	vector<int> s(n);
	for (auto& x : s) {
		cin >> x;
	}

	vector<long long> ans(n + 1);
	for (int i = 0; i < n; ++i) {
		sort(b[i].begin(), b[i].end(), [&](const int x, const int y) {
			return s[x] > s[y];
		});
		int m = (int)b[i].size();
		if (!m) {
			continue;
		}
		vector<long long> sum(m);
		sum[0] = s[b[i][0]];
		for (int j = 1; j < m; ++j) {
			sum[j] = sum[j - 1] + s[b[i][j]];
		}
		for (int j = 1; j <= m; ++j) {
			int limit = m / j * j;
			ans[j] += sum[limit - 1];
		}
	}

	for (int i = 1; i <= n; ++i) {
		cout << ans[i] << " \n"[i == n];
	}
}
posted @ 2025-03-10 10:11  _Yxc  阅读(10)  评论(0)    收藏  举报