Description
详见OJ
Solution
考场就刚\(T1\)了。。。
首先打了个暴力:\(dfs\)枚举选哪些数,然后\(K^2DP\)求出答案。
设\(f[i][j]\)表示前\(i\)个人有\(j\)个选好的方案数。答案即为\(f[K][K/2]\)。
从题解发现,选的人是一段前缀和一段后缀。
茹氏证明:
我们可以固定\(K-1\)个人以及他们选什么。
我们设\(s1\)表示有\(K/2-1\)人选好,\(K/2\)人选坏的概率。
\(s2\)表示\(K/2\)人选好,\(K/2-1\)人选坏的概率。
那么对于答案,即为\(s1*p+s2*(1-p)\)。
若\(s1>s2\),那么肯定的我们要使p尽可能大,反之亦然。
不断如此,结果选的人一定为一段前缀和一段后缀。
用DP求解即可。
Code
#include <cstdio> #include <algorithm> #define N 2010 #define db double #define mem(x, a) memset(x, a, sizeof x) #define fo(x, a, b) for (int x = a; x <= b; x++) #define fd(x, a, b) for (int x = a; x >= b; x--) using namespace std; int n, K; db p[N], f[N][N], g[N][N], s, ans; inline bool cmp(db x, db y) {return x < y;} int main() { freopen("vote.in", "r", stdin); freopen("vote.out", "w", stdout); scanf("%d%d\n", &n, &K); fo(i, 1, n) scanf("%lf", &p[i]); sort(p + 1, p + n + 1, cmp); f[0][0] = 1; fo(i, 1, K) { f[i][0] = f[i - 1][0] * (1 - p[i]); fo(j, 1, i) f[i][j] = f[i - 1][j - 1] * p[i] + f[i - 1][j] * (1 - p[i]); } g[n + 1][0] = 1; fd(i, n, n - K + 1) { g[i][0] = g[i + 1][0] * (1 - p[i]); fo(j, 1, n - i + 1) g[i][j] = g[i + 1][j - 1] * p[i] + g[i + 1][j] * (1 - p[i]); } fo(i, 0, K) { s = 0; fd(j, min(i, K / 2), 0) s += f[i][j] * g[n - K + i + 1][K / 2 - j]; if (s > ans) ans = s; } printf("%.9lf\n", ans); return 0; }
该题好像满足三分性,但我不会证,以下代码AC了:
#include <cstdio> #include <algorithm> #define N 2010 #define db double #define mem(x, a) memset(x, a, sizeof x) #define fo(x, a, b) for (int x = a; x <= b; x++) #define fd(x, a, b) for (int x = a; x >= b; x--) using namespace std; int n, K, cs, now; db p[N], f[N][N], c[N], s, s1, ans; inline bool cmp(db x, db y) {return x < y;} void solve() { f[0][0] = 1; fo(i, 0, K - 1) { fd(j, K / 2, 0) f[i + 1][j] = 0; fd(j, min(i, K / 2), 0) { f[i + 1][j] += f[i][j] * (1 - c[i + 1]); f[i + 1][j + 1] += f[i][j] * c[i + 1]; } } } int main() { freopen("vote.in", "r", stdin); freopen("vote.out", "w", stdout); scanf("%d%d\n", &n, &K); cs = K / 2; fo(i, 1, n) scanf("%lf", &p[i]); sort(p + 1, p + n + 1, cmp); int l = 0, r = K, mid, mid1; if (K < n) { while (l <= r) { mid = l + (r - l) / 3; mid1 = r - (r - l) / 3; fo(i, 1, mid) c[i] = p[i]; fo(i, mid + 1, K) c[i] = p[n - K + i]; solve(); s = f[K][K / 2]; fo(i, 1, mid1) c[i] = p[i]; fo(i, mid1 + 1, K) c[i] = p[n - K + i]; solve(); s1 = f[K][K / 2]; if (s > s1) ans = s, r = mid1 - 1; else ans = s1, l = mid + 1; } } fo(i, 1, l) c[i] = p[i]; fo(i, l + 1, K) c[i] = p[n - K + i]; solve(); s = f[K][K / 2]; if (s > ans) ans = s; printf("%.9lf\n", ans); return 0; }