JZOJ Day 2-A组-T1-贿赂

J Z   D a y   2 − A ​ JZ\ Day\ 2-A​ JZ Day 2A − T 1 ​ − -T1​- T1贿赂


题目:

议会里有 N ​ N​ N个议员,每个议员有两个属性:级别和忠诚值。

现在你要在议会通过一个议案,一个议案通过当且仅当严格超过一半的议员投赞同票。一个议员投赞同票的几率就是忠诚值除以 100 ​ 100​ 100

议员们有着奇怪的癖好:他们都喜欢吃糖。你带了 K ​ K​ K个糖果用来贿赂议员,每个糖果的作用是使得某个议员的忠诚值增加 10 ​ 10​ 10。贿赂要在投票开始前完成。(注意任意议员的忠诚值不可能大于 100 ​ 100​ 100

投票之后,如果议案没有通过,你就会很暴力地把投了反对票的所有议员暗杀掉。假设你要暗杀的议员集合是 S ​ S​ S,那么成功率就是 A / ( A + B ) ​ A/(A+B)​ A/(A+B);其中A是给定的常数,B是S中所有议员级别的和。当暗杀成功后你的议案就会获得通过。

现在要求最优贿赂方案下最大的成功几率是多大。

对于100%的数据,保证N,K≤9,A,ai≤9999,bi是10的倍数。


解题思路:

数据比较小,所以我们直接dfs分糖再枚举所有投票情况, 求出概率然后再取最大值。


Accepted code:

#include
#include

using namespace std;

int _, N, K;
double sum, ans, A;
double a[15], b[15];

double read() {
     
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)) {
      if (c == '-') f = -f; c = getchar(); }
	while(isdigit(c)) x = (x<<1) + (x<<3) + c - 48, c = getchar();
	return (double)x * f;
}

void check(int dep, int c, double k, double z) {
     
	if (!k) return;
	if (dep == N) {
     
		if (c >= _) sum += k;
		else sum += k * A / (A + z);
		return;
	}
	check(dep+1, c+1, k*a[dep+1], z);
	check(dep+1, c, k*(1-a[dep+1]), z+b[dep+1]);
}

void dfs(int dep, int c) {
     
	if (!c) {
     
		sum = 0;
		check(0, 0, 1, 0);
		ans = max(sum, ans);
		return;
	}
	if (dep == N) return;
	for (int i = 0; i <= c; ++i) {
     
		double j = (double)i * 1e-1;
		if (a[dep+1] + j <= 1.0001) {
     
			a[dep+1] += j;
			dfs(dep+1, c-i);
			a[dep+1] -= j; 
		} else break;
	}
}

int main() {
     
	scanf("%d %d", &N, &K); A = read();
	_ = N / 2 + 1;
	for (int i = 1; i <= N; ++i)
		b[i] = read(), a[i] = read() / 1e2;
	dfs(0, K);
	printf("%.6lf", ans);
}

你可能感兴趣的:(纪中模拟赛,dfs,枚举)