列表

详情


NC20549. [HEOI2015]小L的白日梦

描述

在某一天,你有了一个女性朋友。 你打算利用k天时间陪她,每天有很多种娱乐方式可供选择,你需要从中选择一种进行(一天只能进行一个项目),比如说一起去看电影、一起去主题公园,一起去逛街等等,一共n种项目。
当然每个项目重复太多次你都会觉得无聊,因此第i个项目最多进行c[i]次。你虽然智商很高,但是情商堪忧,即使这些你准备的活动都是希望让她开心的,不过由于你笨拙的语言表达和过于理智的行动,可能使这些活动出现意外。
经过你悉心的计算,你发现如果某一天进行了第i个项目,如果一切顺利的话她应该是很高兴的,但她会有a[i]的概率不高兴。如果她本来是很高兴的,但突然今天你让她不高兴了,她就会觉得很失落,并且对你的好感度大大下降。你希望尽可能避免这种情况发生,因此你要安排这k天之内每天进行的项目,最小化她感到失落的期望次数。 
 你的女性朋友十分在意你,所以她的心情只会因为你发生改变。第一天之前,因为你没有邀请她进行任何活动,所以她是不高兴的。

输入描述

第一行有一个非负整数t,表示一共有t组数据。
对于每组数据,第一行有两个非负整数n,k,分别表示你准备的项目个数和你用来陪她的天数。(n ≤ 10^5, k ≤ 10^9)
接下来n行,每一行描述一个项目,形如“x[i]/y[i] c[i]”且三个数均为非负整数,表示进行完这个项目之后她有x[i]/y[i]的概率不高兴,并且这个项目只能进行不超过c[i]次。
(x[i],y[i] ≤ 104,c[i] ≤ 10^9)

输出描述

一共t行,对于每组数据输出使她感到失落的最小期望次数,四舍五入保留6位小数。

示例1

输入:

3
1 2
0/1 3
1 2
1/1 3
1 2
1/2 3

输出:

0.000000
0.000000
0.250000

说明:

【样例说明】
考虑第三组数据,因为只有一个项目所以只好每天都安排这个。
在第一天之前她总是不高兴的,一共有:
第一天不高兴,第二天也不高兴、
第一天高兴,第二天不高兴、
第一天不高兴,第二天高兴、
第一天不高兴,第二天也不高兴,
这四种情况,又因为每天的项目让她高兴或者是不高兴的概率都是0.5,因此这四种情况是等概率发生的。
只有在第二种情况下,她会感到失落一次。
因此答案是(1*1+0*3)/4=0.25.

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 321ms, 内存消耗: 3548K, 提交时间: 2022-10-25 15:15:06

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 100100
#define double long double
const double eps=1e-10;
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
struct Node{double p;int c;}p[MAX];
bool cmp(Node a,Node b){return a.p>b.p;}
int n,K;
int main()
{
	int T=read();
	while(T--)
	{
		n=read();K=read();
		for(int i=1;i<=n;++i)
		{
			int x=read(),y=read();
			p[i].p=1.0*x/y,p[i].c=read();
		}
		sort(&p[1],&p[n+1],cmp);
		int l=1,r=n,t;
		while(!p[l].c)++l;while(!p[r].c)--r;
		p[l].c-=1;p[r].c-=1;K-=2;
		double pl=p[l].p,pr=p[r].p;
		double ans=0;
		while(K)
		{
			while(!p[l].c)++l;
			while(!p[r].c)--r;
			if(1-pl>pr)
			{
				if(fabs(pr-p[r].p)>eps)t=1;
				else t=min(K,p[r].c);
				ans+=(1-p[r].p)*pr+(t-1)*(1-p[r].p)*p[r].p;
				K-=t;p[r].c-=t;pr=p[r].p;
			}
			else
			{
				if(fabs(pl-p[l].p)>eps)t=1;
				else t=min(K,p[l].c);
				ans+=(1-pl)*p[l].p+(t-1)*(1-p[l].p)*p[l].p;
				K-=t;p[l].c-=t;pl=p[l].p;
			}
		}
		ans+=(1-pl)*pr;
		printf("%.6Lf\n",ans);
	}
	return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 487ms, 内存消耗: 5688K, 提交时间: 2022-10-25 16:08:49

#include<bits/stdc++.h>
using namespace std;
void solve(){
	int n,k;
	scanf("%d %d",&n,&k);
	std::pair<long double,int> p[100010];
	for(int i=1,x,y;i<=n;i++){
		scanf("%d/%d %d",&x,&y,&p[i].second),p[i].first=1.*x/y;
		if(!p[i].second) --n,--i;
	}
	std::sort(p+1,p+n+1,std::greater());
	if(k==1) return puts("0.000000"),void();
	long double pl=p[1].first,pr=p[n].first;
	int l=1,r=n;
	k-=2,p[1].second--,p[n].second--;
	long double ans=0;
	while(k){
		while(!p[l].second) ++l;
		while(!p[r].second) --r;
		int x;
		if(pl+pr>=1){
			if(p[l].first==pl) x=std::min(k,p[l].second);	
			else x=1;
			k-=x,p[l].second-=x;
			ans+=(1-pl)*p[l].first+(x-1)*(1-p[l].first)*p[l].first;
			pl=p[l].first;
		}else{
			if(p[r].first==pr) x=std::min(k,p[r].second);
			else x=1;
			k-=x,p[r].second-=x;
			ans+=(1-p[r].first)*pr+(x-1)*(1-p[r].first)*p[r].first;
			pr=p[r].first;
		}
	}
	ans+=(1-pl)*pr;
	printf("%.6Lf\n",ans);
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--) solve();
	return 0;
}

上一题