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