Codeforces - 994B: pair型优先队列 and Codeforces - 992B

<Codeforces 994B>

题意:

给定一个 n,一个 k,表示有n个骑士,这n个骑士有相应的等级和价值,每个骑士最多可以杀比他等级低的 k 个人,被杀了的骑士的价值,会累加到杀了人的骑士身上,骑士可以重复被人杀,但是杀了人的骑士获得的价值,不会在被杀时累加到杀人骑士身上,即每个骑士获得的价值,就是被他杀了的那些骑士原本的价值的和,问这些骑士最后能获得的价值是多少。题以解释起来有点拗口。。。看一眼样例就一目了然啦~

思路:

首先了解到,骑士有两个属性,等级和价值,所以很自然想到 pair,题意就是贪心,转化过来就是,每个骑士要杀至多 k 个等级比他低的骑士,且要求所杀的骑士价值和最大。这题我第一反应是结构体排序,但是想试试用优先队列操作一下,下面简述一下我大概的思路:

首先定义一个 typedef pair <int,int> PR;

再定义一个PR a[maxn];  表示输入的具备以下两个属性的这些骑士。

first属性代表价值,second属性代表等级,有人可能会问,为什么输入的时候,后输入的是价值,但却把它定义成first属性呢~?这是因为,pair类型的优先队列,默认自动按照first属性降序排列,而我们根据题意操作,就是要在等级低于当前骑士的骑士中,取前k大的价值,即让价值降序排列。声明优先队列如下:

priority_queue <PR> qua; //pair型的优先队列自动按照first降序排

这样剩下的等级自然就成了second属性了,而此时第一个贪心条件已经满足,就是取前k大的价值,第二个贪心条件,就是要控制等级比当前骑士低,所以此时声明一个cmp( )函数,让a[maxn]按照second属性升序排列,如下:

bool cmp(PR x, PR y) { return x.second < y.second; }

声明一个map,进行当前角标的维护,因为排完序角标就乱了,但是还要按照原来的位置输出每个骑士的价值,即t[i] = a[i].second,然后初始化mp[ t[i] ] 值为 a[i].first,即:

mp.clear();
cin >> n >> k;
for(int i = 1; i <= n; i++) {
	cin >> a[i].second;
	t[i] = a[i].second; //为了对应原来的位置, 即角标
}
for(int i = 1; i <= n; i++) {
	cin >> a[i].first;
	mp[t[i]] = a[i].first; //初始化这些骑士的价值为自身价值
}

按照cmp( )进行sort排序之后,这些骑士等级就按照升序排列了,接下来是核心代码:

for(int i = 1; i <= n; i++) {
	int cnt = 0; //每个骑士的杀人数
	while(!qua.empty() && cnt < k) {
		mp[a[i].second] += qua.top().first;
		q[++cnt] = qua.top();
		qua.pop();
	}
	qua.push(a[i]);
	for(int j = 1; j <= cnt; j++) qua.push(q[j]);
}

由于mp记录的是价值,循环走到 i 位置时,所以需要对等级为 a[i].second的骑士进行价值的累加,而累加的是每次优先队列队头的first属性,即价值,操作为:

mp[a[i].second] += qua.top().first;

然后把被杀掉的这个骑士存进q[ ]数组,q[ ]数组也要用PR声明,然后弹出队头,接着向后扫,当已经杀了k个骑士,或者没杀到k个,但是剩下的骑士等级都高于当前骑士,即没法杀的时候,也就是队列空的时候,循环结束,这时要把当前骑士压进队列,看他下一个骑士要不要杀他,然后再把他杀过的骑士,也重新压进队列,理由和压进当前其实自身相同。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cctype>
#include <ctime>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
const int Inf = 1e9 + 7;
int n, k;

typedef pair <int, int> PR; //first记录骑士的价值, second记录骑士的等级
PR a[maxn];
PR q[12]; //每次被杀死的骑士, 即重新入队的元素
priority_queue <PR> qua; //pair型的优先队列自动按照first降序排

int t[maxn]; //对应角标位置的数组, 因为排序完最后输出结果仍要保持原来的位置
map <int, ll> mp; //mp[t[i]]即为答案

bool cmp(PR x, PR y) { return x.second < y.second; }

int main() {
	mp.clear();
	cin >> n >> k;
	for(int i = 1; i <= n; i++) {
		cin >> a[i].second;
		t[i] = a[i].second; //为了对应原来的位置, 即角标
	}
	for(int i = 1; i <= n; i++) {
		cin >> a[i].first;
		mp[t[i]] = a[i].first; //初始化这些骑士的价值为自身价值
	}
	sort(a + 1, a + n + 1, cmp); //按等级(second)升序
	for(int i = 1; i <= n; i++) {
		int cnt = 0; //当前骑士杀人数
		while(!qua.empty() && cnt < k) {
			mp[a[i].second] += qua.top().first;
			q[++cnt] = qua.top();
			qua.pop();
		}
		qua.push(a[i]);
		for(int j = 1; j <= cnt; j++) qua.push(q[j]);
	}
	for(int i = 1; i <= n; i++) cout << mp[t[i]] << " ";
	cout << endl;
} 

<Codeforces 992B>

题意:

给定一段闭区间 [l,r],区间长度最长是1e9,再给定两个数x,y。在区间内选取两个数i,j 组成一个二元组<i,j>或者<j,i>,使得gcd(i,j) = x 且 lcm(i,j) = y。若 i != j,则<i,j>和<j,i>算两个二元组,否则算一个,问能找到多少个二元组。

思路:

首先明确一点,会写lcm( )函数的都知道,lcm(a,b) = a * b / gcd(a,b)。

即 a * b = lcm(a,b) * gcd(a,b),转化为题干中变量就是:i * j = x * y。

又 y = lcm(i,j) 为 i,j 的最小公倍数,换句话说,i,j 都是 y 的因子。

所以 sqrt(y) 枚举 y 的所有因子 i 即可,然后构造二元组的另一元素 j,j = x * y / i,再看 gcd(i,j) 是否为 x即可。

那么我就写一个bool型返回值的Chk( )判断枚举出来的因子能否构成二元组,如下:

bool Chk(ll a) { //判断a能否构成二元组
	bool flg = 1;
	ll mul = x * y;
	ll b = mul / a;
	if(a * b != mul) flg = 0;
	if(a < l || a > r) flg = 0;
	if(b < l || b > r) flg = 0;
	if(gcd(a, b) != x) flg = 0;
	return flg;
}

没啥难度的,就看一下能不能mul能不能整除枚举出来的因子,能整除的话,除数就是二元组里的另一个元素,判一下越界,再判一下gcd即可。

然后进行如下枚举和计数操作,判一下找的因子相不相同即可,代码如下:

for(ll i = 1; i <= sqrt(y); i++) {
	if(y % i) continue; //枚举因子
	ll t = y / i;
	if(Chk(i)) ans++;
	if(t != i && Chk(t)) ans++;
}

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <stack>
#include <cctype>
#include <ctime>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int Inf = 1e9 + 7;
const int maxn = 1e5 + 7;
typedef pair <int, int> pr;
priority_queue <pr> qua;
vector <int> vect;
set <int> sst;
map <int, int> mp;
ll l, r, x, y;
ll ans;

ll gcd(ll x, ll y) {
	if(x % y == 0) return y;
	else return gcd(y, x % y);
}

bool Chk(ll a) { //判断a能否构成二元组
	bool flg = 1;
	ll mul = x * y;
	ll b = mul / a;
	if(a * b != mul) flg = 0;
	if(a < l || a > r) flg = 0;
	if(b < l || b > r) flg = 0;
	if(gcd(a, b) != x) flg = 0;
	return flg;
}

int main() {
	cin >> l >> r >> x >> y;
	for(ll i = 1; i <= sqrt(y); i++) {
		if(y % i) continue; //枚举因子
		ll t = y / i;
		if(Chk(i)) ans++;
		if(t != i && Chk(t)) ans++;
	}
	cout << ans << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章