jzoj 6296. 【NOIP提高组A】投票

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;
}

猜你喜欢

转载自www.cnblogs.com/jz929/p/11366467.html