test20181006 投票

题意


分析

考场30分

枚举大小为k的子集的算法终于用上了。
时间复杂度

\[O\left(\binom{n}{k} \cdot \binom {k}{\frac{k}{2}} \cdot k\right) \]

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
    T data=0;
	int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=20;
int n,k;
double p[MAXN],t[MAXN];
int len;

int next(int comb)
{
	int x = comb & -comb,y = comb + x;
	comb=(((comb & ~y) / x) >> 1) | y;
	return comb;
}

int main()
{
  freopen("vote.in","r",stdin);
  freopen("vote.out","w",stdout);
	read(n);read(k);
	for(int i=0;i<n;++i)
	{
		scanf("%lf",p+i);
	}
	double maxv=0;
	for(int i=(1<<k)-1;i<(1<<n);i=next(i))
	{
//		cerr<<"i="<<i<<endl;
		len=0;
		for(int j=0;j<n;++j)
			if(i&(1<<j))
				t[len++]=p[j];
//		cerr<<"len="<<len<<endl;
		double ans=0;
		for(int j=(1<<(len/2))-1;j<(1<<len);j=next(j)) // len=k
		{
//			cerr<<" j="<<j<<endl;
			double sum=1;
			for(int s=0;s<len;++s)
			{
				if(j&(1<<s))
				{
//					cerr<<"  mul 1 "<<t[s]<<endl;
					sum*=t[s];
				}
				else
				{
					sum*=(1.0-t[s]);
//					cerr<<"  mul 2 "<<(1.0-t[s])<<endl;
				}
			}
//			cerr<<" sum="<<sum<<endl;
			ans+=sum;
		}
		maxv=max(maxv,ans);
	}
	printf("%lf\n",maxv);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

标解

解释一下

  1. 所谓的贡献,就是把其他的看成常量,用i同学来计算的计算式。
  2. 换成前后至少有一个不劣。
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
    T data=0;
	int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=2e3+7;
int n,k;
double p[MAXN],pre[MAXN][MAXN],suf[MAXN][MAXN];

int main()
{
  freopen("vote.in","r",stdin);
  freopen("vote.out","w",stdout);
	read(n);read(k);
	for(int i=1;i<=n;++i)
		scanf("%lf",p+i);
	sort(p+1,p+n+1);
	
	pre[0][0]=1;
	for(int i=1;i<=n;++i)
	{
		double p=::p[i];
		for(int j=n;j>=1;--j)
			pre[i][j]=p*pre[i-1][j-1]+(1-p)*pre[i-1][j];
		pre[i][0]=(1-p)*pre[i-1][0];
	}
	
	suf[n+1][0]=1;
	for(int i=n;i>=1;--i)
	{
		double p=::p[i];
		for(int j=n;j>=1;--j) // 从n到1保证不会被自己更新
			suf[i][j]=p*suf[i+1][j-1]+(1-p)*suf[i+1][j];
		suf[i][0]=(1-p)*suf[i+1][0];
	}
	
	int m=k/2;
	double ans=0;
	for(int i=0;i<=k;++i)
	{
		int j=n+1-k+i; // n-x+1=k-i -> x=n+1-k+i
		double sum=0;
		for(int ci=0;ci<=m;++ci)
			sum+=pre[i][ci]*suf[j][m-ci];
		ans=max(ans,sum);
	}
	
	printf("%.9f\n",ans);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

posted on 2018-10-06 15:59  autoint  阅读(196)  评论(0编辑  收藏  举报

导航