题解 luogu.【XR-3】小道消息 & luogu.[NOIP 2009 提高组] Hankson 的趣味题
题目
luogu.P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题
luogu.[NOIP 2009 提高组] Hankson 的趣味题
两道考察同一个结论的题目。我们主要证明一下这个结论,建模是非常朴素的。所以重点还是数学的演绎推理。
题意建模
都说可以模拟。确实如此。但是这样只能拿到部分分。我们还是手推一下这些定理与性质。
算法分析
这两个题无非就考了一个枚举,一个 \(\gcd()\) 函数,所以实现并不难。结合代码,发现都有这么一句:
for(int i=1;i<=y/i;i++)
if(y%i==0)
{
if(gcd(i,y/i*x)==x) cnt++;
if(y/i!=i)
if(gcd(y/i,i*x)==x)
cnt++;
}
以及:
for(int x=1;x<=b1/x;x++)
if(b1%x==0)
{
if(gcd(x,a0)==a1 && lcm(x,b0)==b1) ans++;
if(b1/x!=x)
if(gcd(b1/x,a0)==a1 && lcm(b1/x,b0)==b1)
ans++;
}
这个代码片段是题的核心,依赖的是以下这个定理:
若
\(\left\{ \begin{array}{rcl}
a_{1}=\gcd(x,a_{0}),\\
b_{1}=lcm(x,b_{0})\\
\end{array}\right.
\),
且有
\(\left\{ \begin{array}{rcl}
a_{1}|a_{0},\\
b_{0}|b_{1},\\
x|b_{1}\\
\end{array}\right.
\),
则:
\(\left\{ \begin{array}{rcl}
a_{1}=\gcd(b_{1}/x,a_{0})\\
b_{1}=lcm(b_{1}/x,b_{0})\
\end{array}\right.
\)
这是很显然的。只需要导出 \(b_{1}/x \geqslant x\) ,以及\(a_{1}|x\),即可知道 \(a1|b_{1}/x\),所以就得证了。
只有在结合代码的时候,上述结论成立,因为有一个很强的条件是 \(b_{1}/x \geqslant x\)。
这是由代码中的枚举顺序决定了的。
参考代码
#include<iostream>
using namespace std;
int gcd(int x,int y) { return y?gcd(y,x%y):x; }
int cnt;
int main()
{
int x,y,p,q; cin>>x>>y;
for(int i=1;i<=y/i;i++)
if(y%i==0)
{
if(gcd(i,y/i*x)==x) cnt++;
if(y/i!=i)
if(gcd(y/i,i*x)==x)
cnt++;
}
cout<<cnt<<endl;
return 0;
}
#include<iostream>
using namespace std;
int gcd(int x,int y){ return y?gcd(y,x%y):x; }
int lcm(int x,int y){ return y/gcd(x,y)*x; }
void solve()
{
int a0,a1,b0,b1; cin>>a0>>a1>>b0>>b1;
int ans=0;
for(int x=1;x<=b1/x;x++)
if(b1%x==0)
{
if(gcd(x,a0)==a1 && lcm(x,b0)==b1) ans++;
if(b1/x!=x)
if(gcd(b1/x,a0)==a1 && lcm(b1/x,b0)==b1)
ans++;
}
cout<<ans<<endl;
}
int main()
{
int t; cin>>t;
while(t--) solve();
return 0;
}
细节实现
注意不要爆 int 就可以。还要特判,不是完全平方数。
总结归纳
就是一个小结论。

浙公网安备 33010602011771号