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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章