【Codeforces #142 Div1】Solutions

A、B、C题题解请移步http://www.cnblogs.com/Delostik/archive/2012/10/03/2710655.html

  

【D. Towers】

  http://www.codeforces.com/contest/229/problem/D

  题目大意:有n座塔,每次操作可以将第i座塔和第(i-1)座或第(i+1)座合并,新塔高度为两塔高度和。问最少多少次操作之后使得塔高度序列不降。

  O(n^2)的方法:f[i]表示使前i座塔高度不降的最少操作次数,h[i]表示在执行f[i]操作的前提下,第i座塔(或者是由操作i合并成的新塔)的最小高度。

     f[i]=min{f[j]},sum(j,i)>=h[j-1],0≤j≤i ; h[i]=sum(j,i)

  预处理前缀和,枚举i,j,完毕。

  里面用到一个贪心性质就是,离i最近的j肯定是最优的……因为如果有状态j'<j,f[j]=f[j'],那么h[j']>h[j]这是显然的……这就没必要了……

  有人说单调队列……其实用单调队列实质上也是要枚举,没看出有什么实质性的不一样……

#include <iostream>
using namespace std;

int n,H,f[5010],sum[5010],h[5010];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>H;
		sum[i]=sum[i-1]+H;
	}
	for(int i=1;i<=n;i++)
		for(int j=i-1;j>=0;j--)
			if(sum[i]-sum[j]>=h[j]){
				f[i]=f[j]+i-j-1;
				h[i]=sum[i]-sum[j];
				break;
			}
	cout<<f[n]<<endl;
}

 

【E. Gifts】

  http://www.codeforces.com/contest/229/problem/E

  题目大意:有一些礼物,有些礼物有相同的名字单有不同的价格,有些礼物有相同的价格但可以有不同的名字。人喊一个礼物的名字,便会随机得到叫这个名字的其中一个礼物。问取得n个最大价值的礼物的概率是多少。

  “名字相同的礼物有不同的价格”,这句话很重要。我们确定一个价值下限minv,那么在所有礼物里面有两类,一类是一定要选的(v[i]>minv),另一类是价值恰好等于minv,可能选其中的一部分。那句话就告诉我们,在每种名字的礼物中,最多有1个是可以选择“选”或者“不选”的。

  于是我们把第二类挑出来单独搞,称它们为“可选礼物”。可知可选礼物个数choose=n-cnt个,cnt为价值大于minv的礼物数量。

  f[i][j]表示前i种名字的礼物中,选取了j个可选的礼物。num[i]表示名字为i个礼物个数,must[i]表示名字为i的礼物中的必选礼物个数。

  转移:1.若第i种名字的礼物中没有可选礼物,那么f[i][j]=f[i-1][j]/C(must[i],num[i])

     2.若第i种名字的礼物中有可选礼物,那么令t=(n-cnt-j)/choose,表示在第i种礼物中选取一个可选礼物的概率。

    f[i][j]=f[i-1][j]/C(must[i],num[i])*(1-t)     在i种中不选可选礼物

    f[i][j+1]=f[i-1][j]/C(must[i],num[i]+1)*t   在i种中选可选礼物

#include <iostream>
#include <vector>
#include <iomanip>
#include <algorithm>
#define mn 1010
using namespace std;

vector<int> v[mn];
int n,m,x,minv,choose,cnt,tot,a[mn],must[mn],num[mn];
double C[mn][mn],f[mn][mn],tmp;
bool prob[mn];

int main(){
	for(int i=0;i<=1000;i++){
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>num[i];
		for(int j=1;j<=num[i];j++){
			cin>>x;
			v[i].push_back(x);
			a[++tot]=x;
		}
	}
	sort(a+1,a+1+tot);
	minv=a[tot-n];
	for(int i=1;i<=m;i++){
		for(int j=0;j<v[i].size();j++)
			if(v[i][j]>minv) cnt++,must[i]++;
			else if(v[i][j]==minv) prob[i]=true;
		choose+=prob[i];
	}
	f[0][0]=1;
	for(int i=1;i<=m;i++){
		for(int j=0;j<=n-cnt;j++)
			if(!prob[i]) f[i][j]=f[i-1][j]/C[num[i]][must[i]];
			else{
				tmp=(double)(n-cnt-j)/choose;
				f[i][j]+=f[i-1][j]/C[num[i]][must[i]]*(1-tmp);
				f[i][j+1]+=f[i-1][j]/C[num[i]][must[i]+1]*tmp;
			}
		choose-=prob[i];
	}
	cout<<fixed<<setprecision(10)<<f[m][n-cnt]<<endl;
}

 

posted @ 2012-10-03 03:01  Delostik  阅读(383)  评论(0编辑  收藏  举报