UVa10375 - Choose and divide

/*UVa10375 - Choose and divide
--考查素数因子唯一分解定理。将x!分解成素数因子,然后再进行相乘约分。考虑效率问题:组合数公式进行化简:
 C(m,n)=m*(m-1)*...(m-n+1)/n!来计算.
*/
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<string.h>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn =10000+5;

bool vis[maxn];
int prime[maxn];  //10000素数表
int pri[maxn];
int pnum;  //素数个数

//生成素数表
int Euler(int n){
	memset(vis, 0, sizeof(vis));
	int phi = 0;
	for (int i = 2; i <= n; i++){
		if (!vis[i]){ prime[phi++] = i;};  //i是素数
		for (int j = 0; j < phi&&i*prime[j] <= n; j++){
			vis[i*prime[j]] = 1;   //筛去
			if (i%prime[j] == 0)break;  //i是合数(当前是合法的),并且这个数已经被筛过
		}
	}
	return phi; //返回素数个数
}
void add_integer(int n, int d){
	for (int i = 0; i < pnum; i++){
		while (n%prime[i] == 0){ n /= prime[i]; pri[i]+=d; }

		if (n == 1)break;
	}
}
//加入a*(a-1)*...(a-b+1)的素数因子
void add_factorial(int a, int b, int d){
	for (int i = 0; i < b;i++)
		add_integer(a-i, d);
}
int main(){
	int p, q, r, s;
	pnum = Euler(10000);
	while (~scanf("%d%d%d%d", &p, &q, &r, &s)){
		memset(pri, 0, sizeof(pri));
		q = min(q, p - q);
		s = min(s, r - s);
		add_factorial(p, q, 1);
		add_factorial(r, s, -1);
		if (s > q)add_factorial(s, s-q, 1);  //开始这里写出一个bug搞搞死我了
		else add_factorial(q, q-s, -1);
		double ans = 1.00;
		for (int i = 0; i < pnum; i++)
			ans *= pow(prime[i], pri[i]);
		printf("%.5lf\n",ans);
	}
	return 0;
}

  

posted @ 2016-08-24 16:58  曹孟德  阅读(115)  评论(0)    收藏  举报