zoukankan      html  css  js  c++  java
  • $UVA10288$ 优惠券 $Coupons$

    链接

    背景

    (UVA10288)

    题意

    对于多组数据,每次给出 (n) 种卡片,每种抽出来的概率相同。求集齐 (n) 种卡片需要抽取的次数的期望。若答案不为整数请以带分数形式输出。第一行输出分子,第二行输出整数部分和分数线(中间以一个空格隔开),第三行输出分母。分数线的长度和分母相同,分子、分母、分数线需要左对齐。要求最终结果的分数部分不可约。

    解法

    整体过程显然是不好考虑的。不妨从其中的一小部分着手。假设当前已经抽出了 (k) 种卡片。则抽出还没有抽到过的卡片的概率为 (frac{n-k}{n}) ,即 (n) 种可能结果中的 (n-k) 种要求的结果。根据概率与期望的关系,显然这一次抽到一种新卡的期望次数为 (frac{n}{n-k}) 。则对于整个过程就是从 (0) 种卡抽到 (1) 种新卡,从 (1) 种卡抽到第 (2) 种新卡, (cdots cdots) 直到抽出第 (n) 种新卡。
    因此总的期望次数就是 (sum_limits{k in [0,n)} frac{n}{n-k}) ,也即 (sum_limits{k in [1,n]} frac{n}{k})(O(n)) 计算即可。
    为了以分数形式输出,需要分别处理分子分母,每次求和时就模拟分数相加的过程通分即可。
    为了输出最简分数(同时避免分子(母)爆 (long) (long) ),需要边乘边约分(求最大公约数同除去即可)。

    (trick)

    一个非常用不经典套路:对于不便于计算的整体过程,不妨拆成很小的部分着手,观察变化,可窥知整体规律。

    代码

    $View$ $Code$
    
    //省略头文件
    using namespace std;
    inline int read()
    {
    	int ret=0,f=1;
    	char ch=getchar();
    	while(ch>'9'||ch<'0')
    	{
    		if(ch=='-')
    			f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		ret=(ret<<1)+(ret<<3)+ch-'0';
    		ch=getchar();
    	}
    	return ret*f;
    }
    int n,len1,len2;
    long long numerator,denominator;
    long long gcd(long long a,long long b)
    {
    	return b?gcd(b,a%b):a;
    }
    int main()
    {
    	while(scanf("%d",&n)!=EOF)
    	{
    		numerator=1ll;
    		denominator=1ll;
    		for(register int i=2;i<=n;i++)
    		{
    			numerator=numerator*i+denominator;
    			denominator*=i;
    			long long fac=gcd(numerator,denominator);
    			numerator/=fac;
    			denominator/=fac;
    		}
    		numerator*=n;
    		long long fac=gcd(numerator,denominator);
    		numerator/=fac;
    		denominator/=fac;
    		if(denominator==1)
    			printf("%lld
    ",numerator);
    		else
    		{
    			long long integer=numerator/denominator,tmp=integer;
    			numerator-=denominator*integer;
    			len1=0;
    			while(tmp)
    			{
    				len1++;
    				tmp/=10;
    			}
    			for(register int i=0;i<=len1;i++)
    				printf(" ");
    			printf("%lld
    ",numerator);
    			printf("%lld ",integer);
    			tmp=denominator;
    			len2=0;
    			while(tmp)
    			{
    				len2++;
    				tmp/=10;
    			}
    			for(register int i=1;i<=len2;i++)
    				printf("-");
    			printf("
    ");
    			for(register int i=0;i<=len1;i++)
    				printf(" ");
    			printf("%lld
    ",denominator);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java并发基础10:原子性操作类的使用
    Java并发基础09. 多个线程间共享数据问题
    Java并发基础08. 造成HashMap非线程安全的原因
    Java并发基础07. ThreadLocal类以及应用技巧
    Java并发基础06. 线程范围内共享数据
    Java并发基础05. 传统线程同步通信技术
    Java并发基础04. 线程技术之死锁问题
    我是如何从通信转到Java软件开发工程师的?
    IOS 判断耳机插入/拔出
    海量数据处理
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11743886.html
Copyright © 2011-2022 走看看