Uva 10375 Choose and divide 素数唯一分解定理
2015-09-15 16:21
429 查看
Description
The binomial coefficient C(m, n) is defined as C(m, n) = m!/((m − n)! n!) Given four natural numbers p, q, r, and s, compute the the result of dividing C(p, q) by C(r, s).
Input
Input consists of a sequence of lines. Each line contains four non-negative integer numbers giving values for p, q, r, and s, respectively, separated by a single space. All the numbers will be smaller than 10,000 with p ≥ q and r ≥ s.
Output
For each line of input, print a single line containing a real number with 5 digits of precision in the fraction,giving the number as described above. You may assume the result is not greater than 100,000,000.
Sample Input
10 5 14 9
93 45 84 59
145 95 143 92
995 487 996 488
2000 1000 1999 999
9998 4999 9996 4998
Sample Output
0.12587
505606.46055
1.28223
0.48996
2.00000
3.99960
题意极其粗暴,就是求组合数C(p,q)/C(r,s)的值,保留五位小数。当然难度在于,四个系数p,q,r,s是10000以内。组合数这玩意啊。。稍微大一点这规模就疯长了,谁叫人家是用阶乘定义的呢?
这就用到了素数唯一分解定理。
素数唯一分解定理:合数p能且仅能有一种方式写成如下形式:
p=(p1)^(e1)*(p2)^(e2)*(p3)^(e3)*...*(pn)^(en)
其中,p1,p2,...pn是小于p的质数,并且p1<p2<p3<...<pn,e1,e2,e3...en是正整数指数。
简单化简得:
我们可以想到,将p,s,r-s,r,q,p-q都作质数分解,那么分子分母都可以写成10000以内的质数分解式,这就可以直接操作指数了。声明一个数组e,保存每个素数在式子中对应的指数。将最终的指数得到之后,就可以算最终结果了。
实现这一点,要事先得到10000以内的所有素数(这个题的规模在10000以内),这个题里面可以用最粗暴的方法得到,229MS通过
其中get和solve函数是唯一分解定理的实现
然后我总觉得粗暴求素数时间开销略大,于是写了个筛法来作预处理
init1和init2函数是筛法实现
结果。。。。216MS通过。。这tmd也没怎么优化啊。。
The binomial coefficient C(m, n) is defined as C(m, n) = m!/((m − n)! n!) Given four natural numbers p, q, r, and s, compute the the result of dividing C(p, q) by C(r, s).
Input
Input consists of a sequence of lines. Each line contains four non-negative integer numbers giving values for p, q, r, and s, respectively, separated by a single space. All the numbers will be smaller than 10,000 with p ≥ q and r ≥ s.
Output
For each line of input, print a single line containing a real number with 5 digits of precision in the fraction,giving the number as described above. You may assume the result is not greater than 100,000,000.
Sample Input
10 5 14 9
93 45 84 59
145 95 143 92
995 487 996 488
2000 1000 1999 999
9998 4999 9996 4998
Sample Output
0.12587
505606.46055
1.28223
0.48996
2.00000
3.99960
题意极其粗暴,就是求组合数C(p,q)/C(r,s)的值,保留五位小数。当然难度在于,四个系数p,q,r,s是10000以内。组合数这玩意啊。。稍微大一点这规模就疯长了,谁叫人家是用阶乘定义的呢?
这就用到了素数唯一分解定理。
素数唯一分解定理:合数p能且仅能有一种方式写成如下形式:
p=(p1)^(e1)*(p2)^(e2)*(p3)^(e3)*...*(pn)^(en)
其中,p1,p2,...pn是小于p的质数,并且p1<p2<p3<...<pn,e1,e2,e3...en是正整数指数。
简单化简得:
我们可以想到,将p,s,r-s,r,q,p-q都作质数分解,那么分子分母都可以写成10000以内的质数分解式,这就可以直接操作指数了。声明一个数组e,保存每个素数在式子中对应的指数。将最终的指数得到之后,就可以算最终结果了。
实现这一点,要事先得到10000以内的所有素数(这个题的规模在10000以内),这个题里面可以用最粗暴的方法得到,229MS通过
其中get和solve函数是唯一分解定理的实现
#include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<cstring> #include<vector> #include<string> #include<cmath> #include<stack> //#define file #define maxn 100010 #define inf 0x3f3f3f3f #define LL long long using namespace std; int p,q,r,s; double ans; int fac[10010]; vector<int>prime; bool check(int n) { for(int i=2;i<n;i++) { if(n%i==0) return false; } return true; } void init() { prime.push_back(2); for(int i=3;i<=10000;i++) { if(check(i)) { prime.push_back(i); } } } void get(int p,int q) { for(int i=0;i<prime.size();i++) { while(p%prime[i]==0) { p/=prime[i]; fac[i]+=q; } if(p==1)break; } } void solve(int p,int q) { for(int i=1;i<=p;i++) { get(i,q); } } int main() { init(); while(cin>>p>>q>>r>>s) { memset(fac,0,sizeof(fac)); solve(p,1); solve(s,1); solve(r-s,1); solve(r,-1); solve(q,-1); solve(p-q,-1); ans=1; for(int i=0;i<prime.size();i++) { ans*=pow(prime[i],fac[i]); } printf("%.5f\n",ans); } }
然后我总觉得粗暴求素数时间开销略大,于是写了个筛法来作预处理
init1和init2函数是筛法实现
#include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<cstring> #include<vector> #include<string> #include<cmath> #include<stack> //#define file #define maxn 100010 #define inf 0x3f3f3f3f #define LL long long using namespace std; int p,q,r,s; double ans; int fac[10010]; int vis[10010]; vector<int>prime; void init1() { int m=sqrt(10000+0.5); memset(vis,0,sizeof(vis)); for(int i=2;i<=m;i++) { if(!vis[i]) { for(int j=i*i;j<=10000;j+=i) vis[j]=1; } } } void init2() { init1(); for(int i=2;i<=10000;i++) { if(!vis[i]) prime.push_back(i); } } void get(int p,int q) { for(int i=0;i<prime.size();i++) { while(p%prime[i]==0) { p/=prime[i]; fac[i]+=q; } if(p==1)break; } } void solve(int p,int q) { for(int i=1;i<=p;i++) { get(i,q); } } int main() { init2(); while(cin>>p>>q>>r>>s) { memset(fac,0,sizeof(fac)); solve(p,1); solve(s,1); solve(r-s,1); solve(r,-1); solve(q,-1); solve(p-q,-1); ans=1; for(int i=0;i<prime.size();i++) { ans*=pow(prime[i],fac[i]); } printf("%.5f\n",ans); } }
结果。。。。216MS通过。。这tmd也没怎么优化啊。。
相关文章推荐
- ORM对象关系映射之GreenDAO源码解析
- ”增量更新“Java程序员转安卓开发
- struts2 标签
- Ruby on Rails服务器文件上传
- SQL触发器实例
- A标签伪类
- PHP mysqli(数据库操作)
- Vmware vSphere 5.0 vSphere网络原理及vSwitch简介
- C++内存管理
- linux之sed用法
- vim 的使用方法
- 配置IIS服务器支持Sencha Touch
- 使用Jenkins配置自动化构建
- iOS开发之 手势
- cocos2dx-3.X中对事件处理分析(1)
- mongodb备份还原脚本
- CocoaPods是什么?
- 循环队列-顺序存储结构-数据结构
- 黑马程序员android 事件分发机制
- linux下共享内存mmap和DMA(直接访问内存)的使用 2014-08-13 09:31:40 blog.chinaunix.net/uid-7374279-id-4413316.html