Noip2009 Hankson的趣味题
Posted hankeke
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Noip2009 Hankson的趣味题相关的知识,希望对你有一定的参考价值。
Description
Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson。现
在,刚刚放学回家的Hankson 正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数(c_1) 和(c_2) 的最大公约数和最小公倍数。现
在Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公
倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数(a_0),(a_1),(b_0),(b_1),设某未知正整
数x 满足:
1. (x) 和(a_0) 的最大公约数是(a_1);
2. (x) 和(b_0) 的最小公倍数是(b_1)。
Hankson 的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的
(x) 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的(x) 的个数。请你帮
助他编程求解这个问题。
Input
第一行为一个正整数(n),表示有(n) 组输入数据。接下来的n 行每
行一组输入数据,为四个正整数(a_0),(a_1),(b_0),(b_1),每两个整数之间用一个空格隔开。输入
数据保证(a_0) 能被(a_1) 整除,(b1) 能被(b_0) 整除。
Output
每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的 (x),请输出0;
若存在这样的 (x),请输出满足条件的(x)的个数;
Sample Input
2
41 1 96 288
95 1 37 1776
Sample Output
6
2
Hint
【说明】
第一组输入数据,(x) 可以是9、18、36、72、144、288,共有6 个。
第二组输入数据,(x) 可以是48、1776,共有2 个。
【数据范围】
对于 50%的数据,保证有1≤(a_0),(a_1),(b_0),(b_1)≤10000 且n≤100。
对于 100%的数据,保证有1≤(a_0),(a_1),(b_0),(b_1)≤2,000,000,000 且n≤2000。
题解
90分算法
我们把题目的内容表示一下
[
left{
egin{align*}
gcd(a_0,x)&=a_1lcm(b_0,x)&=b_1\end{align*}
ight.
]
显然,x一定是(b_1)的因数,一定是(a_1)的倍数。假设m表示(a_0),(a_1),(b_0),(b_1)的大小,我们可以(O(sqrt m))枚举(b_1)的约数x,然后判断x满不满足上面的方程组即可。由于gcd和lcm的时间复杂度都是(O(log m)),有(n)次询问,所以总时间复杂度为(O(n sqrt m log m))。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
template<typename A>inline void read(A&a){a=0;A f=1;int c=0;while(c<'0'||c>'9'){c=getchar();if(c=='-')f*=-1;}while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}a*=f;}
template<typename A,typename B>inline void read(A&a,B&b){read(a);read(b);}
template<typename A,typename B,typename C>inline void read(A&a,B&b,C&c){read(a);read(b);read(c);}
typedef long long ll;
int T;
int a0,a1,b0,b1,ans;
inline int gcd(int x,int y){return x%y==0?y:gcd(y,x%y);}
inline int lcm(int x,int y){return x/gcd(x,y)*y;}
inline bool check(int x){return gcd(x,a0)==a1&&lcm(x,b0)==b1;}
void Init(){
read(a0,a1);
read(b0,b1);
ans=0;
}
void Work(){
int t=sqrt(b1);
for(register int i=1;i<=t;++i){
if(!(b1%i)){
if(check(i))++ans;
if(b1/i!=i)if(check(b1/i))++ans;
}
}
printf("%d
",ans);
}
int main(){
read(T);
while(T--){
Init();
Work();
}
return 0;
} //鉴于这个代码是我一年前写的,所以如果码风不大正常还请见谅。
这个算法在当年Noip的时候可以拿90分,但是在洛谷神机和codevs里面就可以过了。
100分做法
我们把上面的式子再放一遍。
[
left{
egin{align*}
gcd(a_0,x)&=a_1lcm(b_0,x)&=b_1\end{align*}
ight.
]
因为(x)是(b_1)的约数,所以x的质因子一定是(b_1)拥有的。所以我们可以对于p的每一个质因子,计算x可以拥有多少个。
我们枚举(b_1)的质因数p,设(a_0),(a_1),(b_0),(b_1)的分别有(m_{a_0}),(m_{a_1}),(m_{b_0}),(m_{b_1})个,x有(m_x)个。
对于(gcd(a_0,x)=a_1)这个式子,我们有三种情况:
[
left{
egin{align*}
m_{a_0} > m_{a_1} quad &Rightarrow quad m_x = m_{a_1}m_{a_0} = m_{a_1} quad &Rightarrow quad m_x geq m_{a_1}m_{a_0} < m_{a_1} quad &Rightarrow quad ext{无解}\end{align*}
ight.
]
对于(lcm(b_0,x)=b_1)这个式子,我们也有如下三种情况:
[
left{
egin{align*}
m_{b_0} > m_{b_1} quad &Rightarrow quad ext{无解}m_{b_0} = m_{b_1} quad &Rightarrow quad m_x leq m_{b_1}m_{b_0} < m_{b_1} quad &Rightarrow quad m _x = m_{b_1}\end{align*}
ight.
]
那么我们现在把上面集中情况整合一下:有如下几种情况:
[
left{
egin{align*}
m_{a_0} > m_{a_1} , m_{b_0} < m_{b_1} , m_{a_1} = m_{b_1} qquad &Rightarrow qquad m_x ext{有$1$中取法}m_{a_0} > m_{a_1} , m_{b_0} = m_{b_1} , m_{a_1} leq m_{b_0} qquad &Rightarrow qquad m_x ext{有$1$中取法}m_{a_0} = m_{a_1} , m_{b_0} < m_{b_1} , m_{a_0} leq m_{b_1} qquad &Rightarrow qquad m_x ext{有$1$中取法}m_{a_0} = m_{a_1} , m_{b_0} = m_{b_1} , m_{a_1} leq m_{b_1} qquad &Rightarrow qquad m_x ext{有$m_{b_1}-m_{a_1}+1$中取法}\text{其他情况} qquad &Rightarrow qquad ext{无解}\end{align*}
ight.
]
我们把(cnt_p)表示(m_x)的取值个数,(无解即为0),那么我们只要求出
[pi limits_{ ext{质数}p|d}{s} cnt_p]
以上是关于Noip2009 Hankson的趣味题的主要内容,如果未能解决你的问题,请参考以下文章
NOIP2009Hankson 的趣味题[唯一分解定理|暴力]
Luogu P1072 NOIP2009 Hankson的趣味题暴力