1. 程式人生 > >Codeforces 798D Mike and distribution(貪心或隨機化)

Codeforces 798D Mike and distribution(貪心或隨機化)

amp 後來 int 都是 讓我 spa turn mes 題目

題目鏈接 Mike and distribution

題目意思很簡單,給出$a_{i}$和$b_{i}$,我們需要在這$n$個數中挑選最多$n/2+1$個,使得挑選出來的

$p_{1}$,$p_{2}$,$p_{3}$,...,$p_{m}$滿足

$a_{p1}+a_{p2}+a_{p3}+...+a_{p_{m}}>a_{1}+a_{2}+a_{3}+...+a_{n}$

$b_{p1}+b_{p2}+b_{p3}+...+b_{p_{m}}>b_{1}+b_{2}+b_{3}+...+b_{n}$

$m <= n/2+1$

打這場比賽的時候怎麽也想不到……眼睜睜看著自己掉分

後來看了別人的代碼才恍然大悟。

貪心做法:

因為$a_{i}$和$b_{i}$都是正數,那麽就直接令$m = n/2+1$

先對$a$降序排序,然後排完序之後的$1$號必選

然後在剩下$n-1$個數中,每相鄰兩個數分成一組,在每一組中選$b_{i}$較大的那個,就可以了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

struct node{
	int x, y, id;
} a[100010];
int n;
set <int> s;

int main(){

	scanf("%d", &n);
	rep(i, 1, n) scanf("%d", &a[i].x);
	rep(i, 1, n) scanf("%d", &a[i].y);
	rep(i, 1, n) a[i].id = i;
	
	sort(a + 1, a + n + 1, [](node a, node b){return a.x > b.x;});

	s.insert(a[1].id);
	for (int i = 2; i <= n; i += 2){
		int j = i + 1;
		if (j <= n && a[j].y > a[i].y) s.insert(a[j].id); else s.insert(a[i].id);
	}

	printf("%d\n", n / 2 + 1);
	for (auto u : s) printf("%d\n", u);

	return 0;
}

不過這道題還有另一種解法……那就是……隨機化……

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define LL		long long

const int N = 100010;

LL a[N], b[N], A = 0, B = 0;
int p[N], n, k;

int main(){

	scanf("%d", &n);
	rep(i, 1, n) scanf("%d", a + i), A += a[i];
	rep(i, 1, n) scanf("%d", b + i), B += b[i];

	rep(i, 1, n) p[i] = i;
	srand(time(0)); 
	k = n / 2 + 1;

	while (true){
		LL x = 0, y = 0;
		random_shuffle(p + 1, p + n + 1);
		rep(i, 1, k) x += a[p[i]], y += b[p[i]];
		if (2 * x > A && 2 * y > B){
			printf("%d\n", k);
			rep(i, 1, k) printf("%d\n", p[i]);
			return 0;
		}
	}

	return 0;
}

真的讓我驚呆了……

Codeforces 798D Mike and distribution(貪心或隨機化)