UVa 10288 Coupons

题目链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1229


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <utility>
using namespace std;


// result[i]分别记录n为i时的分子和分母
pair<long long, long long> result[35];

pair<long long,long long> get_result(pair<long long,long long> r1, pair<long long,long long> r2);

long long gcd(long long x, long long y);

int main()
{
	// 计算所有情况
	for(int i = 1; i <= 33; i++)
	{
		if(i == 1)
			result[i] = pair<long long,long long>(1, 1);
		else
		{
			// 计算两个分数相加的结果
			result[i] = get_result(result[i-1], pair<long long,long long>(1, i));
		}		
	}	

	for(int i = 1; i <= 33; i++)
	{
		result[i].first = result[i].first * i;
		long long x = gcd(result[i].first, result[i].second);
		result[i].first = result[i].first / x;
		result[i].second = result[i].second / x;	
	}

	// 读入情况
	char up_str[100];
	char down_str[100];
	char int_str[100];
	int n;
	while(scanf("%d", &n) == 1)
	{
		// 打印整数和分数部分
		long long t_int = result[n].first / result[n].second;
		long long t_up = result[n].first % result[n].second;

		if(t_up == 0)
			printf("%lld\n", t_int);
		else
		{
			memset(up_str, 0, sizeof(up_str));
			memset(down_str, 0, sizeof(down_str));

			sprintf(up_str, "%lld", t_up);
                        sprintf(down_str, "%lld", result[n].second);	
			int len = max(strlen(up_str), strlen(down_str));

			if(t_int == 0)
			{
				printf("%lld\n", t_up);
				for(int i = 0; i < len; i++)
					printf("-");
				printf("\n%lld\n", result[n].second);		
			}		
			else
			{
				memset(int_str, 0, sizeof(int_str));	
				sprintf(int_str, "%lld", t_int);
	
				int int_len = strlen(int_str);
				for(int i = 0; i <= int_len; i++)
					printf(" ");
				printf("%lld\n", t_up);
				printf("%lld ", t_int);
				for(int i = 0; i < len; i++)
					printf("-");
				printf("\n");
				for(int i = 0; i <= int_len; i++)
                                        printf(" ");            
                                printf("%lld\n", result[n].second);		
			}
		}

						
	}
	return 0;	
}


// 计算两个分数相加的结果
pair<long long,long long> get_result(pair<long long,long long> r1, pair<long long,long long> r2)
{
	long long now_up = r1.first*r2.second + r2.first*r1.second;
	long long now_down = r1.second*r2.second;
	
	long long x = gcd(now_up, now_down);
	return pair<long long,long long>(now_up/x, now_down/x);			
}

// 计算两数的最大公约数
long long gcd(long long x, long long y)
{
	if(x < y)
		return gcd(y, x);
	else
	{
		if(y == 0)
			return x;
		else
			return gcd(y, x % y);
	}
			
}


一道经典的概率题。

用到了期望线性性和几何分布的期望。

设Y为收集n个奖券的开包次数

设Yi为收集了i-1个奖券,想要收集到第i个奖券需要的开包次数。

则Y = Y1+Y2+ ... + Yn.

E[Y] = E[Y1+Y2+ ... + Yn] = E[Y1]+E[Y2]+ ... +E[Yn].

由于Yi为几何分布,得到第i个奖券的概率p为(n-(i-1)) / n

E[Yi] = 1/p.

则E[Y] = n/1 + n/2 + n/3 + ... + n/n. 为O(nlogn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值