zoukankan      html  css  js  c++  java
  • 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, &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;
    }
    
    转载需注明出处。
  • 相关阅读:
    NC13950 Alliances(LCA)
    NC13884 Paint Box(容斥原理)
    Gym102174B 炼金术(AC自动机)
    CF301D Yaroslav and Divisors(树状数组)
    CF1443D Extreme Subtraction(思维)
    Gym102174L 旅行的意义(期望dp)
    Gym102220F Mini-game Before Contest(博弈论)
    Gym102220D Master of Data Structure (虚树)
    用random.simple来解决从0-99这100个数中随机取10个不重复的数
    一个栈的输入序列为1,2,3,4,5,则下列序列中不可能是栈的输出序列的是()
  • 原文地址:https://www.cnblogs.com/jz929/p/11366467.html
Copyright © 2011-2022 走看看