C. Berland Regional

题:
Polycarp is an organizer of a Berland ICPC regional event. There are n universities in Berland numbered from 1 to n. Polycarp knows all competitive programmers in the region. There are n students: the i-th student is enrolled at a university ui and has a programming skill si.

Polycarp has to decide on the rules now. In particular, the number of members in the team.

Polycarp knows that if he chooses the size of the team to be some integer k, each university will send their k strongest (with the highest programming skill s) students in the first team, the next k strongest students in the second team and so on. If there are fewer than k students left, then the team can’t be formed. Note that there might be universities that send zero teams.

The strength of the region is the total skill of the members of all present teams. If there are no teams present, then the strength is 0.

Help Polycarp to find the strength of the region for each choice of k from 1 to n.

Input
The first line contains a single integer t (1≤t≤1000) — the number of testcases.

The first line of each testcase contains a single integer n (1≤n≤2⋅10^5) — the number of universities and the number of students.

The second line of each testcase contains n integers u1,u2,…,un (1≤ui≤n) — the university the i-th student is enrolled at.

The third line of each testcase contains n integers s1,s2,…,sn (1≤si≤10^9) — the programming skill of the i-th student.

The sum of n over all testcases doesn’t exceed 2⋅10^5.

Output
For each testcase print n integers: the strength of the region — the total skill of the members of the present teams — for each choice of team size k.

Example
input
4
7
1 2 1 2 1 2 1
6 8 3 1 5 1 5
10
1 1 1 2 2 2 2 3 3 3
3435 3014 2241 2233 2893 2102 2286 2175 1961 2567
6
3 3 3 3 3 3
5 9 6 7 9 7
1
1
3083
output
29 28 26 19 0 0 0
24907 20705 22805 9514 0 0 0 0 0 0
43 43 43 32 38 43
3083

Note
In the first testcase the teams from each university for each k are:

k=1:
university 1: [6],[5],[5],[3];
university 2: [8],[1],[1];
k=2:
university 1: [6,5],[5,3];
university 2: [8,1];
k=3:
university 1: [6,5,5];
university 2: [8,1,1];
k=4:
university 1: [6,5,5,3];

题意:
给定n个学生和两行数组,第一行是学校名,第二行是该学校对应学生的能力值。限制团队成员k,那么每所大学将把他们最强的k个(具有最高编程技能的)学生派到第一个团队,下一个最强的k个学生派到第二个团队,以此类推。如果剩下的学生少于k,那么这个团队就不能成立。注意,有些大学可能不派出任何团队。
输出k从1到n的所有大学派出团队的总能力值。

思路:
用一个二维的vector容器去分别存储各学校名和对应的学生能力值,然后分别将各学校学生的能力值从大到小排序。
用一个pair对象去存储学校的学生人数和学校名,同时分别求每个学校学生能力值的前缀和。
将pair对象根据每个学校的学生人数从小到大排序。
剪枝操作:可以在求k从1到n时学校的能力值和时将那些小于k的学校直接pass掉,免去重复遍历。

ps:这题有思路,不过当时被各个学校分别排序难住了QAQ,刚用vector、pair,感觉真的好方便诶。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std ;

#define ll long long
const ll N = 2e5 + 7 ;
ll t , n , a[N] , b[N] , sum[N] ;
vector< ll > ho[N] ; //二维 
pair< ll , ll > pos[N] ;

bool cmp( ll a , ll b )
{
	return a > b ;
}

int main()
{
	ios::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;
	
	cin >> t ;
	while( t-- )
	{
		cin >> n ;
		
		//清0 
		for( int i = 1 ; i <= n ; ++i )
		{
			ho[i].clear() ;
			sum[i] = 0 ;
		}
		
		for( int i = 1 ; i <= n ; ++i )
		{
			cin >> a[i] ;
		}
		for( int i = 1 ; i <= n ; ++i )
		{
			cin >> b[i] ;
		}
		
		//根据学校放入能力值 
		for( int i = 1 ; i <= n ; ++i )
		{
			ho[a[i]].push_back(b[i]) ;
		}
		
		//分别将每个学校的能力值从大到小排序 
		for( int i = 1 ; i <= n ; ++i )
		{
			sort( ho[i].begin() , ho[i].end() , cmp ) ;
		}
		
		//分别求每个学校能力值的前缀和 
		for( int i = 1 ; i <= n ; ++i )
		{
			ll len = ho[i].size() ;
			pos[i].first = len ;
			pos[i].second = i ;
			for( int j = 1 ; j < len ; ++j )
			{
				ho[i][j] += ho[i][j-1] ;
			}
		}
		
		//根据每个学校的人数从小到大排序 
		sort( pos + 1 , pos + 1 + n ) ;
		
		int p = 1 ;
		for( int i = 1 ; i <= n ; ++i )
		{
			//剪枝操作
			//那些人数小于k的学校可以直接pass掉,免重复 
			while( p <= n && pos[p].first < i )
			{
				p++ ;
			}
			 
			for( int j = p ; j <= n ; ++j )
			{
				ll len = pos[j].first ;
				ll now = pos[j].second ;
				ll to = len - len % i ;
				sum[i] += ho[now][to-1] ;
			}
		}
		
		for( int i = 1 ; i <= n ; ++i )
		{
			cout << sum[i] << " " ;
		}
		cout << endl ;
	}
	return 0 ;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值