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, &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
", 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, &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
", ans);
return 0;
}