【NOIP 2009】Hankson的趣味题 分析&渣程序(增补对于大质数的分析)
来源:互联网 发布:初中教育状况网络调研 编辑:程序博客网 时间:2024/05/21 11:17
说实话我本来是懒得写题解的。。但是这道题实在是做得太蛋疼了。而且翻了翻网上又没有什么很详细的分析,所以就打算自己来写一篇= =先上题目。
题目描述
Hanks博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson正在思考一个有趣的问题。 今天在课堂上,老师讲解了如何求两个正整数c1和c2的最大公约数和最小公倍数。现在Hankson认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:
已知正整数a0,a1,b0,b1,设某未知正整数x满足:
1. x和a0的最大公约数是a1;
2. x和b0的最小公倍数是b1。
Hankson的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的 x并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x的个数。请你帮助他编程求解这个问题。
输入
输入文件名为son.in。第一行为一个正整数n,表示有n组输入数据。接下来的n行每行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证a0能被a1整除,b1能被b0整除。
输出
输出文件名为son.out。输出共n行。每组输入数据的输出结果占一行,为一个整数。 对于每组数据:若不存在这样的x,请输出0; 若存在这样的x,请输出满足条件的x的个数;
样例输入
241 1 96 28895 1 37 1776
样例输出
62
提示
说明】 第一组输入数据,x 可以是9、18、36、72、144、288,共有6 个。 第二组输入数据,x 可以是48、1776,共有2 个。 【数据范围】 对于 50%的数据,保证有1≤a0,a1,b0,b1≤10000 且n≤100。 对于 100%的数据,保证有1≤a0,a1,b0,b1≤2,000,000,000 且n≤2000。
首先我们不难知道,对于某一个x,gcd(x/a1,a0/a1) = 1,gcd(b1/x , b1/b0) = 1。
在题目中,由于只是求出满足条件x的个数,因此,我们只需要明白x的构成有多少种方案即可。
由唯一分解定理可得,x必定是由若干个质数的若干次幂构成,即x = a1^b1 * a2^b2 *.....*an^bn
因此,我们只需要了解质数及它的次幂有多少种选择即可。
由于x是与a0,a1,b0,b1密切相关的,所以我们现在分解这四个数。
假设对于某个质因数p,a0,a1,b0,b1分别含有c_a0,c_a1,c_b0,c_b1个p。
那么,若c_a1 > c_a0 或 c_b0 > c_b1,则无解:
由最大公约数和最小公倍数的性质可得:a0 % a1 = 0,b1 % b0 = 0。
当a1和a0约去c_a0个p,b1和b0约去c_b1个p后,就会发现,此时a0 % a1 != 0,b1 % b0 != 0(a1和b0中多出了一些p无法被整除)
因此无解。
若c_a1 < c_a0 或 c_b1 > c_b0,则x只能含有c_a1或c_b1个p,即只有一种选择:
同样由上面的推导,由于x % a1 = 0,b1 % x = 0,若c_x > c_a1,而c_a0 > c_a1,则x和a0的最大公约数当然不只a1,起码是 a1 * p^min(c_x - c_a1,c_a0-c_a1)
若c_x < c_a1 ,则x % a1就不可能为0。
用同样的思想,我们可以论证c_b1 > c_b0时只有一种选择。
若c_a1 = c_a0 ,c_b1 = c_b0:
对于前者,这便是c_x的下界。即x至少含有c_a1个p,用前面的方法可以很容易推出。
同理,对于后者,这便是c_x的上界。
因此,c_x的选择一共有(c_b1 - c_a1 + 1)种选择。
最后由乘法原理可得x总的选择数,即答案,下面贴代码(我的渣程序是1s多,应该可以优化。但由于TL是3s,于是过了= =)
#include <cstdio>#define MAXN 50000 //一个数的质因数不会超过它的根号,因此20E的范围开5W的质数表就足矣int prime[MAXN + 20];bool vis[MAXN + 20];int n,cnt,a0,a1,b0,b1,ans;void prime_form() //筛法打出质数表{int i,j;for(i = 2;i <= MAXN;i++)if(!vis[i]){prime[++cnt] = i;for(j = 1;i*j <= 50000;j++)vis[i * j] = true;}}void work_one_step(int &a0,int &a1,int &b0,int &b1,int &result,int p){int cnt1 = 0,cnt2 = 0,cnt3 = 0,cnt4 = 0; //判断a0,a1,b0,b1中质数p的指数while(a0 % p == 0) {cnt1++;a0/=p;}while(a1 % p == 0) {cnt2++;a1/=p;}while(b0 % p == 0) {cnt3++;b0/=p;}while(b1 % p == 0) {cnt4++;b1/=p;}/*gcd(a0/a1,x/a1) = 1,gcd(b1/x,b1/b0) = 1假设对于一个质因数p,a0,a1,b0,b1质因数分解后各有c_a0,c_a1,c_b0,c_b1个p,那么: 如果c_a0<c_a1,无解;如果c_a0=c_a1,x至少含有c_a1个p;如果c_a0>c_a1,那么x只可能含有c_a1个p。如果c_b1<c_b0,无解;如果c_b1=c_b0,x至多含有c_b1个p;如果c_b1>c_b0,那么x只可能含有c_b1个p。*/if(cnt1 == cnt2 && cnt3 == cnt4) //c_a0=c_a1,c_b1=c_b0,在上界大于下界的情况下,可以选择的情况为上界减下界+1{if(cnt3 >= cnt1) result *= (cnt3 - cnt1 + 1);else result *= 0;}if(cnt1 > cnt2 && cnt3 == cnt4) //c_a0>c_a1,c_b1=c_b0,此时x中只可能有c_a1个p,所以c_a1应在上界以内{if(cnt2 <= cnt3) result *= 1;else result *= 0;}if(cnt1 == cnt2 && cnt4 > cnt3) //c_b1>c_b0,c_a0 = c_a1,此时x中只可能含有c_b1个p,所以c_b1要在下界以上{if(cnt4 >= cnt1) result *= 1;else result *= 0;}if(cnt1 > cnt2 && cnt4 > cnt3) //c_a0 > c_a1,c_b1 > c_b1,此时x既要满足只含c_a0个p,又要满足只含c_b1个p,所以c_a0 = c_b1{if(cnt2 == cnt4) result *= 1;else result *= 0;}}int work(int a0,int a1,int b0,int b1){if(a0 % a1 != 0 || b1 % b0 != 0) return 0; //验证数据是否合法的剪枝int result = 1;for(int i = 1;i <= cnt;i++)work_one_step(a0,a1,b0,b1,result,prime[i]);if(a0 != 1) work_one_step(a0,a1,b0,b1,result,a0); //处理超过5W的质数if(b1 != 1) work_one_step(a0,a1,b0,b1,result,b1);return result;}int main(){scanf("%d",&n); prime_form();while(n--) {scanf("%d%d%d%d",&a0,&a1,&b0,&b1);printf("%d\n",work(a0,a1,b0,b1));}return 0;}
P.S渣分析和渣程序见谅= =
增补(笔者极其蛋疼的理论分析,强烈建议略过):
由于之前我的同学和我争论了很久关于除去5W以内的质因数后剩下的大质数处理问题,于是将结论整理后增补于此。
我们设某个超过5W的大质数是P,所谓大质数的问题是指,假设a0 = P x 2,那么对于a0,在质数表的范围内是肯定无法找全质因数的,于是对于剩下的大质数应该特殊处理。
在我之前的代码中,我用来处理大质数的代码是这样的:
if(a0 != 1) work_one_step(a0,a1,b0,b1,result,a0); if(b1 != 1) work_one_step(a0,a1,b0,b1,result,b1);我当时这样做是因为实在是太累了,于是就想偷个懒把所有情况处理了。当然这样做并不会出错,只是没有经过太多分析。
事实上,这段代码可以是这样:
if(a1 != 1) work_one_step(a0,a1,b0,b1,result,a1); else if(b1 != 1) work_one_step(a0,a1,b0,b1,result,b1);或者是这样:
if(a0 != 1) work_one_step(a0,a1,b0,b1,result,a0); if(b1 != 1) work_one_step(a0,a1,b0,b1,result,b1);
(其实就是原来的代码啦= =,现在来加一点分析)
在分析这两段代码前,我们先明确一个事实,即超过5W的大质数P,若有,便在每个数中仅有可能有一个。
并不难想,因为2个及以上的超过5W的数相乘必定大于20E。
那么先来分析第一段代码:
①若a1不含此大质数,即a1最终为1,则此时进入下一if语句。判断b1时,若b1有一个大质数,那么在work_one_step的函数中就会对a0,a1,b0,b1这四个数进行大质数的除法,来保证此大质数影响最终结果的情况。若b1不含大质数,那么x当然也不可能含有这个大质数,而由于此时a1 = 1,所以a0是否含有大质数对于x并不影响。(即c_a1 = 0,c_a0 = 1 或 0,c_b1 = c_b0 = 0,因此c_x的上界为0,那么无论c_a0取1或0,c_x均只能取0,故只有一种选择)
②若a1含此大质数,即a1最终为P,那么x和a0中必然含有P,在第一个work_one_step中便会确定此大质数对于x的影响。
值得一提的是,在②可能会有这样一种特殊情况:即b0含有另一个大质数_P,且b1也含有_P,那么根据之前的规则,x可以含有1个_P或者不含有_P。由于x中已经含有一个大质数P,因此不可能再含_P,即对于_P的选择只能为0。在a1与a0中当然也不可能含有_P,因此x含有_P的下界为0。于是x便只能含有0个_P。即选择只有一种,对最终答案并无影响。
接下来是第二段代码:
①若a0不含此大质数,那么a1就更不可能含大质数。于是就会在下一if语句中判断b1是否含有大质数,来确定大质数对于最终答案的影响。(即对于b1中的大质数P,c_x的下界是0,上界由c_b0和b_b1决定)
②若a0含此大质数,那么就会判断a1,b0,b1是否含有此大质数来改变最终答案。在执行此操作后,需要再判断b1。因为b1有以下三种情况:
I.不含大质数:此时对于结果无影响。
II.含有与a0相同的大质数P:在上个if语句中会被判断出来。
III.含有另一个大质数_P:倘若b0中同样含有这个大质数,那么对于x来说,c_x的上界是1。由于a0,a1不可能再含有_P,即c_a0 = c_a1 = 0,那么c_x的下界为0。此时此时c_x的选择便会是(1 - 0 + 1) = 2种,就会影响到最终结果,因此需要再判断。
P.S. 这一段完全是自己的纯理论分析,没有经过任何的数据验证。但是其实对于这道题的数据而言,有else和没有else都是可以过的。我只是无聊蛋疼的在钻牛角尖而已= =
- 【NOIP 2009】Hankson的趣味题 分析&渣程序(增补对于大质数的分析)
- NOIP-2009-B2 HANKSON 的趣味题
- [NOIP 2009提高] Hankson的趣味题
- 【noip】HankSon的趣味题
- Hankson的趣味题
- Hankson的趣味题
- hankson的趣味题
- NOIP 2009 解题报告(潜伏者,hankson的趣味题,最有贸易,靶形数独)
- Codevs 1172 Hankson 的趣味题 2009年NOIP全国联赛提高组
- Noip 2009 解题报告(潜伏着,Hankson的趣味题,最优贸易,靶形数独)
- NOIP2009 Hankson的趣味题
- Codevs1172 Hankson的趣味题
- NOIP2009 Hankson 的趣味题
- NOIP2009 Hankson的趣味题
- NOIp2009 Hankson的趣味题
- 1172 Hankson 的趣味题
- 【Noip2009】hankson的趣味题
- P1072 Hankson 的趣味题
- 两年未更新博客了
- acm-Arctic Network(最小生成树)
- hdu-2099-整除的尾数
- hdu 1908 Double Queue ( splay )
- 爆搜解hdu1572下沙小面的(2)
- 【NOIP 2009】Hankson的趣味题 分析&渣程序(增补对于大质数的分析)
- POJ - 1061 青蛙的约会 (扩展欧几里得算法)
- java
- 一个二进制算法
- 给大家讲个笑话吧
- 知识点:简单的异常处理,多线程,同步代码块
- disksim与ssd扩展模块小结
- Lucene 工具类
- BadUSB的防范研究