Berland Regional
题解
首先,每个大学本身对答案的贡献是独立的,所以我们可以单独对答案进行计算。
由于当参赛人数大于大学的总人数时,该大学不会对这些答案产生任何贡献,所以对于大学
u
i
u_{i}
ui,我们只需要计算
[
1
,
∣
U
i
∣
]
[1,|U_{i}|]
[1,∣Ui∣]的答案。
计算单个大学的答案时,我们可以先将该大学的人按
s
s
s排序,对于
i
i
i,我们会让前
n
−
n
%
i
n-n\%i
n−n%i个人参加队伍,所以也就是
n
−
n
%
i
n-n\%i
n−n%i的前缀和。
对于每个大学都计算一次它对答案产生的贡献,总时间复杂度 O ( ∑ i = 1 n ∣ U i ∣ l o g ∣ U i ∣ ) = O ( n ) O\left(\sum_{i=1}^{n}|U_{i}|log\,|U_{i}|\right)=O\left(n\right) O(∑i=1n∣Ui∣log∣Ui∣)=O(n)。
然后是另外一种SYDevil巨佬提供的一种
O
(
n
n
)
O\left(n\sqrt{n}\right)
O(nn)的做法,准确说就是当你忘记了对于每个大学只统计到
∣
S
∣
|S|
∣S∣时,可以将这些大学按人数分块,小块就统计到
n
\sqrt{n}
n,大块统计到
n
n
n,其实也没什么特别的。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
const int INF=0x7f7f7f7f;
const int jzm=233;
const int mo=998244353;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int t,n,ui[MAXN],len[MAXN];LL ans[MAXN];
vector<LL>uni[MAXN];
bool cmp(int x,int y){return x>y;}
int main(){
read(t);
while(t--){
read(n);for(int i=1;i<=n;i++)read(ui[i]);
for(int i=1,x;i<=n;i++)read(x),uni[ui[i]].push_back(1ll*x);
for(int i=1;i<=n;i++){
sort(uni[i].begin(),uni[i].end(),cmp);
len[i]=uni[i].size();for(int j=1;j<len[i];j++)uni[i][j]+=uni[i][j-1];
for(int j=1;j<=len[i];j++){
int tmp=len[i]-len[i]%j;
ans[j]+=uni[i][tmp-1];
}
}
for(int i=1;i<=n;i++)printf("%lld ",ans[i]),ans[i]=0;puts("");
for(int i=1;i<=n;i++)uni[i].clear();
}
return 0;
}
分块
int s,fr[200005],B;
vector<ll>a[200005];
vector<int>h,p;
int main(){
for(int T=read;T--;){
s=read;B=sqrt(s)+1;
for(int i=1;i<=s;++i)
a[i].clear();
h.clear();p.clear();
for(int i=1;i<=s;++i)fr[i]=read;
for(int i=1;i<=s;++i)a[fr[i]].push_back(read);
for(int i=1;i<=s;++i){
if(a[i].size()>B)h.push_back(i);
else p.push_back(i);
sort(a[i].begin(),a[i].end());
reverse(a[i].begin(),a[i].end());
for(int j=1;j<a[i].size();++j)
a[i][j]+=a[i][j-1];
}
for(int i=1;i<=s;++i){
ll t=0;
for(int j=0;j<h.size();++j)
t+=a[h[j]].size()<i?0:a[h[j]][a[h[j]].size()/i*i-1];
if(i<=B)
for(int j=0;j<p.size();++j)
t+=a[p[j]].size()<i?0:a[p[j]][a[p[j]].size()/i*i-1];
printf("%lld ",t);
}putchar('\n');
}
return 0;
}