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];
}
}

浙公网安备 33010602011771号