Codeforces Global Round 28 # D

D. Kevin and Competition Memories

一、题意概述

有n个选手和m个问题,给出每个选手的rating---a(n+1),和题目对应的rating---b(m+1),根据rating大小判断选手能否做出这一题。

现在将所有题目分成 [ \frac{k}{m} ] 组,求每组Kevin的排名,求其和,算出和的最小值;

输出m个最小值,k分别等于1,2,···,m 时。

二,思路讲解

要算排名,那么rating低于Kevin的选手对结果就没有影响,所以可以构造一个动态数组a1,使得a1中存的是所有rating大于Kevin的选手(不包括Kevin);

要算排名,比Kevin排名高的选手中,这些选手的排名对Kevin的排名没有影响,那么可以算出每道题的解题人数,而在此之前,可以改变一下b数组,使得答案更容易得出;

当一个题目的rating 小于等于 Kevin 的rating 时,a1中所有选手都可以解决,此时所有人并列第一,所以可以把这道题的rating设置为LONG_MAX,这样所有人都做不出来,结果是一样的,都是第一名,以此,构造出动态数组b1;

此时,就可以构造动态数组c记录每道题的解题人数,Kevin一道题都解不出来,所有Kevin的排名为这组题目中  解题数目的最大值 + 1

然后对c进行排序,每场比赛的最大排名就是 c[ i * k ]+1;i = [ \frac{m}{k} ];

算法

构造a1,b1时可用枚举比较的方法;

构造c的时候最容易想到两层循环,但是 n,m <= 3e5 ,和不超过3e5,这样时间复杂度最大为1e10,会T,所有要优化查找,此时可以使用排序+双指针,因为如果一道题可以被一个选手做出,那么rating比该名选手大的人也可以做出,存在单调性,所以可以将a1,b1排序,然后双指针,这样时间就被优化了。

三、AC代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long

void solve(){
	ll n,m;
	cin >> n >> m;
	vector<ll> a(n+1) , b(m+1);
	for(ll i = 1 ; i <= n ; ++i) cin >> a[i];
	for(ll i = 1 ; i <= m ; ++i) cin >> b[i];
	
	vector<ll> a1;
	a1.push_back(-1);
	for(ll i = 2 ; i <= n ; ++i){
		if(a[i] > a[1]) a1.push_back(a[i]);
	}
	ll tn = a1.size() - 1;
	sort(a1.begin() + 1 , a1.end());
	
	sort(b.begin() + 1 , b.end());
	vector<ll> b1;
	b1.push_back(-1);
	for(ll i = 1 ; i <= m ; ++i){
		if(b[i] > a[1]) b1.push_back(b[i]);
		else b1.push_back(LONG_MAX);
	}
	sort(b1.begin() + 1 , b1.end());
	
	vector<ll> c(m+1,0);
	ll l = 1;
	for(ll i = 1 ; i <= m ; ++i){
		ll f = 0;
		while(l <= tn){
			if(a1[l] >= b1[i]){
				f = 1;
				break;
			}
			else l++;
		}
		if(f == 1) c[i] = tn - l + 1;
		else c[i] = 0;
	}
	
	sort(c.begin() + 1 , c.end());
	
	for(ll k = 1 ; k <= m ; ++k){
		ll ans = 0;
		for(ll i = 1 ; i <= m / k ; ++i){
			ans += c[i*k] + 1;
		}
		cout << ans << " ";
	}
	cout << endl;
}

signed main(){
	ll t;
	cin >> t;
	while(t--){
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值