「CCO 2017」專業網絡

Kevin 正在一個社區中開發他的專業網絡。不幸的是,他是個外地人,還不認識社區中的任何人。但是他可以與 N 個人建立朋友關係 。

然而,社區裏沒幾個人想與一個外地人交朋友。Kevin 想交朋友的 N 個人都有類似但不同的與外地人交友的準則。在 Kevin 已經直接認識了社區中的 Ai 個人後,第 i 個人就願意與 Kevin 交朋友了,否則 Kevin 就要付出 Bi 的代價與他成爲朋友。

你的任務是,使 Kevin 與這 N 個人都交上朋友,並且最小化他付出的代價。

第一行包含整數 N。接下來的 N 行每行包含兩個整數 Ai 和 Bi。

輸出一行一個整數表示 Kevin 付出的最小代價。

題解

首先把所有的人按Ai排序的話,這N個人會形成一條折線,

如果一個一個人地解決掉(以強大的人脈折服他或收買他),那你的人脈的增長會成一條直線,

那麼一個人 i 若在這個序列的位置爲 i' ,且 i' > Ai,則解決這個人是不用花錢的,

這就很像一道叫 “不守交規”的貪心基礎題,

描述

     近些年來,生活水平越來越好,私家車也成了很多家庭必備之物。但某些司機總是不守交規,罰單也是接踵而至。

    有一位不遵守交規的司機,在同一天收到了n條違章罰單短信(1≤n≤100),每條罰單短信中有兩個內容,一:交罰款的最後剩餘時間ti;二:過期未交的滯納金mi(1≤ti,mi≤1000),假設不管過期多少天,滯納金數量不會改變,而且,這位司機很忙,每天最多隻能處理一張罰單,那麼,這位司機應該按怎樣的處理違章短信的順序,才能使滯納金總和最少?

輸入共n+1行

第1行:收到短信數n
後n行:每行分別兩個數,最後期限ti和過期滯納金mi,用空格隔開

輸出

最少的滯納金總和

樣例輸入

4
1 50
1 100
2 60
3 60

樣例輸出

50

解題思路

        首先我們能夠想到按照滯納金的從大到小進行排序,但是真的是按照時間順序處理這些從大到小的滯納金嗎?其實不是的,我們最優貪心思想應該是按照滯納金的按照滯納金的從大到小進行排序,越大的滯納金能夠拖到最後一天處理就最後一天處理;如果最後一天已經處理過以其他的滯納金,則就從這一天倒着往前開始找,看看那一天沒有處理過滯納金,就在這一天處理該滯納金;如果沒有找到,則說明一定要繳納此滯納金。

——————————————————————————————————————————
原文鏈接:https://blog.csdn.net/qq_37220238/article/details/80013402

一樣的思路,把人按Bi從大到小排,然後在 [Ai + 1,n]中找一個最靠左的位置放,位置被佔完了就只能拿錢買他。

只不過得加一個log優化

#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#include<map>
#include<cmath>
#include<iostream>
#define LL long long
using namespace std;
int read() {
    int f = 1,x = 0;char s = getchar();
    while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
    while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
    return x * f;
}
LL max(LL a,LL b) {
	return a > b ? a : b;
}
struct it{
	LL nm,co;
}a[200005];
bool operator < (it a,it b) {
	if(a.co != b.co) return a.co > b.co;
	else return a.nm < b.nm;
}
LL n,m,i,j,k,s,o;
int tre[800005];
int aa[200005];
int bing(int x,int y) {
	if(aa[x] < aa[y]) return x;
	if(aa[x] > aa[y]) return y;
	return x < y ? x : y;
}
void maketree(int n) {
	m = 1;
	while(m < n + 2) m <<= 1;
}
void F5(int x) {
	int s = m + x;
	tre[s] = x;
	s /= 2;
	while(s) {
		tre[s] = bing(tre[s * 2],tre[s * 2 + 1]);
		s /= 2;
	}
	return ;
}
int findt(int l,int r) {
	int s = m + l - 1,t = m + r + 1;
	int ans = 0;
	while(s || t)  {
		if(s / 2 != t / 2) {
			if(s % 2 == 0) {
				ans = bing(ans,tre[s + 1]);
			}
			if(t % 2) {
				ans = bing(ans,tre[t - 1]);
			}
		}
		else break;
		s /= 2;t /= 2;
	}
	return ans;
}
int main() {
	n = read();
	maketree(n + 1);
	for(int i = 1;i <= n;i ++) {
		a[i].nm = read();
		a[i].co = read();
	}
	sort(a + 1,a + 1 + n);a[0].co = 0x7f7f7f7f;
	for(int i = 1;i <= n + 1;i ++) F5(i);aa[0] = 2;
	LL ans = 0;
	for(int i = 1;i <= n;i ++) {
		int j = a[i].nm + 1,k;
//		cout<<j<<endl;
		if((k = findt(j,n + 1)) <= n) {
			aa[k] = 1;
			F5(k);
		}
		else ans += a[i].co;
	}
	printf("%lld\n",ans);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章