[题解]CF 1519C Berland Regional
题意:有很多大学,每个大学有很多学生。每个大学需要组队,组队长度为k,如果人数小于k就无法组队。总的贡献为所有组队选手的能力值之和。现在要统计每个k的总贡献。
这道题唯一涉及到的算法就是一个前缀和优化而已。。。
真正优化的点,在于改变枚举的对象与stl的使用。
对于每个大学,我们按升序排序,然后计算出其前缀和,那么对于
k
k
k,此大学产生的贡献为
s
u
m
[
⌊
n
u
m
[
i
]
k
⌋
∗
k
]
sum\left[\left \lfloor \frac{num[i]}{k} \right \rfloor*k \right]
sum[⌊knum[i]⌋∗k],其中
n
u
m
[
i
]
num[i]
num[i]为第i个大学的人数。
如果我们枚举k,然后对于每个k,计算每个学校的贡献,这种方法很浪费时间。因为,如果一个学校人非常非常多,而其他学校只有一两个人,那么当
k
>
2
k>2
k>2时就严重浪费了。也就是说,对于不同的学校,有用的
k
k
k的上限不同。
所以,如果我们枚举学校,然后对于每个学校,分别按照k计算出贡献,然后存到一个答案数组里面,这样的时间复杂度就会少很多。
注意到,对于每个学校,我们枚举k的上限就是学生的人数,所以时间复杂度为
O
(
n
)
O(n)
O(n)。
再说说stl的使用。其实stl是非常容易超时的。有个好办法是开
O
2
O2
O2优化。虽然辣鸡cf不能用
这里注意,vector如果是在函数内定义,最好指明长度。不然会像我一样T成啥🐕
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
ll u[N];
ll s[N];
ll pre[N];
ll outp[N];
vector<ll> ans[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--){
memset(outp, 0, sizeof outp);
int n;
cin>>n;
set<ll> ss;//set不会存储重复值,用其来存储出现的学校有哪些
for (int i = 1; i <= n;i++){
ans[i].clear();
cin>>u[i];
ss.insert(u[i]);
}
for (int i = 1; i <= n;i++){
cin>>s[i];
ans[u[i]].push_back(s[i]);
}
for(int e : ss){//学校和学校相互独立;如果枚举k的话,有些学校的人数不会到达k,造成很多浪费。
sort(ans[e].begin(), ans[e].end(), greater<ll>());//按降序排
int num = ans[e].size();
for (int i = 1; i <= num;i++){
pre[i] = pre[i - 1] + ans[e][i - 1];//存储每个学校的和
}
for (int i = 1; i <= num;i++){
outp[i] += pre[num / i * i];//存储所有学校的和
}
}
for (int i = 1; i <= n;i++){
cout << outp[i] << ' ';
}
cout << endl;
}
return 0;
}