J Z D a y 2 − A JZ\ Day\ 2-A JZ Day 2−A组 − 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<cstdio>
#include<iostream>
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);
}