题目描述

Hanks 博士是 BT(Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson。现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。

今天在课堂上,老师讲解了如何求两个正整数c_1c1 和 c_2c2 的最大公约数和最小公倍数。现在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a_0,a_1,b_0,b_1a0,a1,b0,b1,设某未知正整数xx 满足:

1. xx 和 a_0a0 的最大公约数是 a_1a1;

2. xx 和 b_0b0 的最小公倍数是b_1b1。

Hankson 的“逆问题”就是求出满足条件的正整数xx。但稍加思索之后,他发现这样的xx 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 xx 的个数。请你帮助他编程求解这个问题。

解析

这道题很容易想出一个比较暴力但是可以AC的解法。

根据题目,我们有\(gcd(a_0,x)=a_1,lcm(x,b_0)=b_1\),那么显然\(a_1\mid x,x\mid b_1\),于是我们找出\(b_1\)的所有质因子,然后验证一下\(a_1\mid x\)是否成立即可。注意在找质因子的时候不要打暴力,肯定会T,应先筛个素数,再用素数凑出\(b_1\),再判断,卡卡常随便过。

如果是在考场上,这种做法无疑是最优的,好想又好写。但是实际上这道题有更好的巧解做法。


由\(lcm(x,b_0)=b_1\)得\(x\mid b_1\),故一定存在一个\(k\),使得\(k\mid x ~\&~ k\mid b_1\),即\(x\)的质因子一定是\(b_1\)的质因子。

由此我们可以想到,我们不妨枚举所有\(1\sim \sqrt{(2*10^9)}\)的所有素数\(k\),并不断将质因子\(k\)从\(a_0,a_1,b_0,b_1\)中除去,同时我们可以通过每个数含有\(k\)的数量确定一些可行的答案。如果最终\(b_1\not= 1\),根据素数理论,说明\(b_1\)本身就是质数。

那么如何通过四个数所含有的\(k\)的数量来判断解的情况呢?

设\(a_0,a_1,b_0,b_1\)分别含有\(ma,mb,mc,md\)个质因子\(k\),\(x\)含有\(mx\)个质因子\(k\),那么我们可以进行如下讨论(可以类比朴素解法的检验过程):

对于\(gcd(x,a_0)=a_1\)这一约束条件:

  1. 当\(ma>mb\)时,有一个解\(mx=mb\);
  2. 当\(ma=mb\)时,有解\(mx>=mb\);
  3. 当\(ma<mb\)时,无解。

对于\(lcm(x,b_0)=b_1\)这一约束条件:

  1. 当\(mc<md\)时,有一个解\(mx=md\);
  2. 当\(mc=md\)时,有解\(mx<=md\);
  3. 当\(mc>md\)时,无解。

故我们可以发现,只要\(ma<mb~||~mc>md\),我们就可以排除当前质因子\(k\)存在解的可能性。而当\(mc=md,ma=mb,mc<=md\)时,有\(md-mb+1\)个解。

要明确一点,我们每次求解的方案数是在质因子\(k\)意义下的解,即\(x\)包含质因子\(k\)的方案数(有点难理解,好好思考)。最终的某个解\(x’\)一定是其中一些符合要求的质因子相乘得到的,因此根据乘法原理,对于每种符合要求的质因子\(k\)能取的方案数,我们累乘到答案中,即可的到所有可行质因子\(k\)最终构成所有\(x\)的数量。(仔细理解质因子\(k\)与答案\(x\)的关系)

设对于质因子\(k\),\(x\)可能包含它的方案数为\(cnt_k\),则最终答案可以表示为:

\[\prod_{k~\mid b_1}~cnt_k
\]

该算法十分高效,却极其难想出来,可谓一种毒瘤解法。。。

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 500010
#define MAX 2000000000
#define MOD 2520
#define E 1e-12
#define ll long long
using namespace std;
ll p[N],v[N],q,m;
ll a0,a1,b0,b1,ans=1;
inline void get(ll n)
{
memset(v,0,sizeof(v));
m=0;
for(int i=2;i<=n;++i){
if(v[i]==0){v[i]=i;p[++m]=i;}
for(int j=1;j<=m;++j){
if(p[j]>n/i||p[j]>v[i]) break;
v[i*p[j]]=p[j];
}
}
}
inline void work(int p)
{
ll ma=0,mb=0,mc=0,md=0;
while(!(a0%p)) a0/=p,ma++;
while(!(a1%p)) a1/=p,mc++;
while(!(b0%p)) b0/=p,mb++;
while(!(b1%p)) b1/=p,md++;
if(ma<mc||mb>md){ans=0;return;}
if(ma==mc&&mb==md){if(mc<=md)ans*=(md-mc+1);else ans=0;return;}
if(((ma>mc)&&(mb==md))||((ma==mc)&&(mb<md))){if(mc<=md)ans*=1;else ans=0;return;}
if((ma>mc)&&(mb<md)){if(mc==md)ans*=1;else ans=0;return;}
}
int main()
{
scanf("%lld",&q);
get(sqrt(MAX));
while(q--){
ans=1;
scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1);
for(int i=1;i<=m;++i)
work(p[i]);
if(a0>1) work(a0);
else if(b1>1&&b1!=a0)
work(b1);
printf("%lld\n",ans);
}
return 0;
}

总结

对于以上两种算法,一点个人理解:暴力算法采用某种自顶向下的判断性求解模式,即判断当前枚举到的\(x\)是否符合条件。更优的算法采用一种类似构造解的模式,根据解的特征自底向上地构造解,应该说是一种较难掌握的思维方式。写完这道题,我想朴素与优雅的算法的区别应该就在这里吧。

P1072 Hankson 的趣味题[数论]的更多相关文章

  1. 洛谷P1072 Hankson 的趣味题

    P1072 Hankson 的趣味题 题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson.现在,刚刚放学回家的 Hankson 正在思考一 ...

  2. 洛谷 P1072 Hankson 的趣味题 解题报告

    P1072 \(Hankson\)的趣味题 题目大意:已知有\(n\)组\(a0,a1,b0,b1\),求满足\((x,a0)=a1\),\([x,b0]=b1\)的\(x\)的个数. 数据范围:\( ...

  3. luogu P1072 Hankson的趣味题

    题目链接 luogu P1072 Hankson 的趣味题 题解 啊,还是noip的题好做 额,直接推式子就好了 \(gcd(x,a_0)=a_1=gcd(\frac{x}{a_1},\frac{a_ ...

  4. Java实现洛谷 P1072 Hankson 的趣味题

    P1072 Hankson 的趣味题 输入输出样例 输入 2 41 1 96 288 95 1 37 1776 输出 6 2 PS: 通过辗转相除法的推导 import java.util.*; cl ...

  5. 1172 Hankson 的趣味题[数论]

    1172 Hankson 的趣味题 2009年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Descrip ...

  6. 洛谷P1072 Hankson 的趣味题(题解)

    https://www.luogu.org/problemnew/show/P1072(题目传送) 数学的推理在编程的体现越来越明显了.(本人嘀咕) 首先,我们知道这两个等式: (a0,x)=a1,[ ...

  7. 洛谷 P1072 Hankson 的趣味题

    题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson.现 在,刚刚放学回家的 Hankson 正在思考一个有趣的问题. 今天在课堂上,老师讲 ...

  8. [NOIP2009] 提高组 洛谷P1072 Hankson 的趣味题

    题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson.现 在,刚刚放学回家的 Hankson 正在思考一个有趣的问题. 今天在课堂上,老师讲 ...

  9. 洛谷P1072 Hankson的趣味题

    这是个NOIP原题... 题意: 给定 a b c d 求 gcd(a, x) = b && lcm(c, x) = d 的x的个数. 可以发现一个朴素算法是从b到d枚举,期望得分50 ...

随机推荐

  1. [神经网络与深度学习][计算机视觉]SSD编译时遇到了json_parser_read.hpp:257:264: error: ‘type name’ declared as function ret

    运行make之后出现如下错误: /usr/include/boost/property_tree/detail/json_parser_read.hpp:257:264: error: 'type n ...

  2. odoo - 自定义默认主页

  3. 09 Spring的依赖注入

    1.依赖注入(Dependency Injection) (1)IOC的作用: 降低程序间的耦合(依赖关系)(2)依赖关系的管理: 以后都交给spring来维护 在当前类需要用到其他类的对象,由spr ...

  4. 【转帖】MySQL用得好好的,为什么要转ES?

    MySQL用得好好的,为什么要转ES? http://developer.51cto.com/art/201911/605288.htm Elasticsearch作为一款功能强大的分布式搜索引擎,支 ...

  5. mysql中数据表记录的增删查改(1)

    数据记录的增删改查 insert into `数据表名称` (`字段名称`, ...) values ('1', ...); delete from `数据表名称` where 子句; update ...

  6. Json 文件读写以及和IniFile 转换

    JSON 文件是越来越受欢迎了,以前程序配置文件用Ini,Ini 简练,简单.方便,但是也有不少缺点,比如,没有 JSON 直观,无法存储复杂点的数据类型. 于是乎,我封装了一个TJsonFile 的 ...

  7. LeetCode第152场周赛(Java)

    这算是我第一次正式参加 LeetCode 的周赛吧.通过两道题.意料之中(通过上次模拟可以看出来).总的来说,脑袋还是不太灵光.想的有点慢.全球第一名 0:10:19 就全部通过...感觉我的智商被狠 ...

  8. 基于 Docker 和 GitLab 的前端自动化部署实践笔记

    基于 Docker 和 GitLab 的前端自动化部署 实践笔记 随着接触的项目越来越多,在部署测试流程上重复耗时工作也越来越多,所以对前端工作的CI/CD实现愈发迫在眉睫. 前端开发由于三大框架的崛 ...

  9. Verilog转电路图

    “你写的不是程序,是电路!”这句话听了很多,大多数人还是搞不太懂.程序怎么能是电路呢?这里将一些典型的Verilog转电路图贴出来,也许可以稍稍理解电路思想了. 1. 2. 3. 4. 5. 6. 7 ...

  10. mysql_新建表:主键、外键等

    序号 命令(中文) 命令(英文呢) 解释 示例 备注 1 主键约束 primary key 不能重复,不能为空 学号 2 外键约束 foreign key 可以重复,依赖主键 学号 3 非空约束 no ...