CodeForces-229E Gifts

题面:

很久很久以前,一位老人和他的妻子住在蔚蓝的海边。有一天,这位老人前去捕鱼,他捉到了一条活着的金鱼。鱼说:“噢,老渔人!我祈求你放我回到海里,这样的话我保证给你n样礼物——任何你想要的礼物!”鱼给了老人一张礼物的清单并附上了礼物的价值。清单上的一些礼物可能会有相同的名称、不同的价值,也可能会有不同的名称、相同的价值。然而,清单上不会出现名称和价值都相同的礼物。

老人可以向鱼索要清单上的n个礼物。老人知道,如果他索要同一个名称s次,那么金鱼会等概率地随机选择该名称下的s样礼物。老人想要满足他贪心的妻子,所以他会选择价值最高的n样礼物。此外,如果有不同的方法选择最高价值的n样礼物,他会等概率地采用其中任意一个方法。

老人想知道,他能拿到n样价值最高的礼物的概率是多少。然而他不怎么擅长概率论,于是就来向你求助。

1 <= n,m <= 1000输入保证所有ki的总和不超过1000, 并且保证n不大于礼物总数。

题意:

给出m个物品组,现在可以要其中的n个物品;

你的策略是这样的:如果有一种方案,可能得到价值最高的n个物品,那么这种方案就是可取的,最终你会从所有可取的方案中随机取一种;

注意:每个物品只有一个,取这n个物品可以认为是同时的;

答案就是得到价值最高的物品的概率;

题解:

这题的题意有些绕。。。而且精度都吓得我上long double了;

实际上很容易想到的是,先按价值大小排序之后,前面有一些是必拿的;

而后面有一价值相同的东西才是有选择的;

那么对于一个物品组,我们需要关心的只有三种属性;

物品组中物品的总个数size,一定要选的物品数must,可能选的物品数can;

但是题中保证了同一个物品组只有一个相同物品,那么这里的can不是0就是1!

暂且不考虑可能选的物品的影响,答案就是1/ΠC[size i][must i];

组合数要提前处理出来,用个long double的1000*1000数组存;

这时我们其实可以暴搜所有方案,随机数据下速度也挺快,但很容易就被卡掉了;

设可以选的物品共有tot个,要从中选出cnt个;

暴搜的复杂度是C[tot][cnt]的,阶乘的增长速度。。。

所以想想不那么暴力的做法,如果物品组i的可选物品被选了,那么它对答案的贡献就由C[size i][must i]变成了C[size i][must i+1];

这之间差的系数我们很容易得到(可以展开拿出公式,也可以直接用处理好的C数组除);

答案求的是随机取方案的概率,也就是所有方案概率的平均数;

考虑一种方案,它的概率可以表示为1/ΠC[size i][must i]/cnt个不同的系数;

那设f[i][j]表示前i个系数,不同的j个乘在一起的和;

转移显然:f[i][j]=f[i-1][j]+系数*f[i-1][j-1];

然后得到的1/ΠC[size i][must i]/C[tot][cnt]/f[tot][cnt]就是答案了;

复杂度不太好算,但是反正不会超过1000*1000,大概也就是O(m^2)咯;

代码:

#include<iomanip>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define N 1100
using namespace std;
typedef long double ld;
int val[N][N],size[N],a[N],tot;
int n,m,tt,cnt,must[N],can[N];
ld C[N][N],fact[N],f[N][N],T[N],ans,mc;
bool cmp(int a,int b)
{
	return a>b;
}
void init()
{
	C[0][0]=1;
	fact[0]=1;
	for(int i=1;i<N;i++)
	{
		fact[i]=fact[i-1]*i;
		C[i][0]=1;
		for(int j=1;j<=i;j++)
		{
			C[i][j]=C[i-1][j]+C[i-1][j-1];
		}
	}
}
void DP()
{
	f[0][0]=1;
	for(int i=1;i<=tt;i++)
	{
		f[i][0]=1;
		for(int j=1;j<=cnt;j++)
		{
			f[i][j]=f[i-1][j]+f[i-1][j-1]*T[i];
		}
	}
}
int main()
{
	int i,j,k;
	scanf("%d%d",&m,&n);
	init();
	for(i=1;i<=n;i++)
	{
		scanf("%d",size+i);
		for(j=1;j<=size[i];j++)
		{
			scanf("%d",&val[i][j]);
			a[++tot]=val[i][j];
		}
		sort(val[i]+1,val[i]+size[i]+1,cmp);
	}
	sort(a+1,a+tot+1,cmp);
	for(i=1,tt=0;i<=n;i++)
	{
		for(j=1;j<=size[i];j++)
		{
			if(val[i][j]>a[m])
				must[i]++;
			else if(val[i][j]==a[m])
			{
				T[++tt]=(ld)(must[i]+1)/(size[i]-must[i]);
				can[i]++;
				break;
			}
			else
				break;
		}
	}
	for(i=m,cnt=0;i>0;i--)
	{
		if(a[m]==a[i])
			cnt++;
		else break;
	}
	for(i=1,mc=1;i<=n;i++)
	{
		mc*=C[size[i]][must[i]];
	}
	DP();
	ans=f[tt][cnt]/C[tt][cnt]/mc;
	cout<<fixed<<setprecision(10)<<ans<<endl;
	return 0;
}
时间: 2024-10-06 06:15:11

CodeForces-229E Gifts的相关文章

CodeForces 681D Gifts by the List

$dfs$,后续遍历. 如果某个节点$a[i]=i$,那么$i$的后继的$a[i]$都要指向$i$,直到出现新的后继$j$,$a[j]=j$.利用这个可以判断是否有解. 如果有解的话,那么只要输出后序遍历的结果就可以了. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include&

CodeForces 681D Gifts by the List (树上DFS)

题意:一个家庭聚会,每个人都想送出礼物,送礼规则是, 一个人,先看名单列表,发现第一个祖先 就会送给他礼物,然后就不送了,如果他没找到礼物 他会伤心的离开聚会!告诉你m个祖先关系, 和每个人想给谁送!让你求出名单列表! 析:这个题,真是没想到啊,还是看的题解,首先要知道的是,如果自己和父结点送的人不一样,并且自己不是给自己的,那么就是无解,为什么呢?是这样的,假设自己和父结点送的人不一样,并且也不是给自己的, 那么一定是给自己的某个祖先,而父结点也是自己的某个祖先,那么不是同一个人,必定一个是另

Codeforces Gym 100187D D. Holidays 排列组合

D. Holidays Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100187/problem/D Description Everyone knows that the battle of Endor is just a myth fabled by George Lucas for promotion of his movie. Actually, no battle of Endor has

Codeforces Round #186 (Div. 2) (ABCDE题解)

比赛链接:http://codeforces.com/contest/313 A. Ilya and Bank Account time limit per test:2 seconds memory limit per test:256 megabytes Ilya is a very clever lion, he lives in an unusual city ZooVille. In this city all the animals have their rights and obl

Codeforces Round #610 (Div. 2) a/b/c

题目 传送门 A Temporarily unavailable   standard input/output 1 s, 256 MB  给一个线段ab, 问除去 c点圆心半径r覆盖的 线段多长,如果圆在线段外 直接输出 ab 长度就行, 若在线段内 则输出cout << max(b-a-max((min(c+r,b)-max(a,c-r)),0), 0) ,迷糊的话纸上画下大概就能明白.B1 K for the Price of One (Easy Version) , B2 K for

Codeforces Round #611 (Div. 3)

原题面:https://codeforces.com/contest/1283 A.Minutes Before the New Year 题目大意:给定时间,问距离零点零分还有多久? 分析:注意一下特判0,0就好了. 代码: t = input() t = int(t) for i in range(t): h, m = input().split() h = int(h) m = int(m) if h == 0 and m == 0: print(0) continue ret = 24

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

Codeforces 124A - The number of positions

题目链接:http://codeforces.com/problemset/problem/124/A Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say that there are no less than a people standing in front of him and no more than b people standing b

Codeforces 841D Leha and another game about graph - 差分

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass th

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st