Hankson的趣味题[NOIP2009]

欢迎大家访问我的老师的OJ———caioj.cn

题面描述

传送门

思路

因为 lcm ⁡ ( x , b 0 ) = b 1 \operatorname{lcm}(x,b_0)=b_1 lcm(x,b0)=b1,所以 x x x b 1 b_1 b1的因数,所以 x x x的质因子一定也是时 b 1 b_1 b1的质因子。我们可以对 b 1 b_1 b1的每个质因子p,计算 x x x可能包含多少个 p p p

a 0 , b 0 , a 1 , b 1 , x a_0,b_0,a_1,b_1,x a0,b0,a1,b1,x分别包含 m a , m b , m c , m d , m x m_a,m_b,m_c,m_d,m_x ma,mb,mc,md,mx个质因子 p p p,其中 m x m_x mx是未知数。

根据最大公约数的定义,在 gcd ⁡ ( a 0 , x ) = a 1 \gcd(a_0,x)=a_1 gcd(a0,x)=a1中:

  1. m a > m c m_a>m_c ma>mc,则 m x = m c m_x=m_c mx=mc
  2. m a &lt; m c m_a&lt;m_c ma<mc,则无解
  3. m a = m c m_a=m_c ma=mc,则 m x ≥ m c m_x\ge m_c mxmc即可

同理,根据最小公倍数的定义,在 lcm ⁡ ( b 0 , x ) = b 1 \operatorname{lcm}(b_0,x)=b_1 lcm(b0,x)=b1

  1. m b &lt; m d m_b&lt;m_d mb<md,则 m x = m d m_x=m_d mx=md.
  2. m b &gt; m d m_b&gt;m_d mb>md,则无解
  3. m b = m d m_b=m_d mb=md,则 m x ≤ m d m_x\le m_d mxmd即可 .

结合两种情况,有以下结论:

  1. m a &gt; m c , m b &lt; m d , m c = m d m_a&gt;m_c,m_b&lt;m_d,m_c=m_d ma>mc,mb<md,mc=md m x = m c = m d m_x=m_c=m_d mx=mc=md
  2. m a &gt; m c , m b = m d , m c ≤ m d m_a&gt;m_c,m_b=m_d,m_c\le m_d ma>mc,mb=md,mcmd m x = m c m_x=m_c mx=mc
  3. m a = m c , m b &lt; m d , m c ≤ m d m_a=m_c,m_b&lt;m_d,m_c\le m_d ma=mc,mb<md,mcmd m x = m d m_x=m_d mx=md
  4. m a = m c , m b = m d , m c ≤ m d m_a=m_c,m_b=m_d,m_c\le m_d ma=mc,mb=md,mcmd m x m_x mx可取 m c m_c mc~ m d m_d md之间的任意值,共有 m d − m c + 1 m_d-m_c+1 mdmc+1种取法。
  5. 其他情况, m x m_x mx 无解.

我们把 m x m_x mx的取法数记为 c n t p cnt_p cntp,也就是 x x x包含质因子 p p p的方案有 c n t p cnt_p cntp种,根据乘法原理,根据题意的 x x x数量即为连乘积:
∏ 质 数 p ∣ d c n t p \prod _{质数p\mid d}cnt_p pdcntp

AC code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long 
using namespace std;
const int N=45010;
const int inf=45000;
const int M=40000;
bool v[N];int prime[M],m;
inline void g_p()
{
	m=0;memset(v,false,sizeof(v));
	for(int i=2;i<=inf;i++)
	{
		if(!v[i])prime[++m]=i;
		for(int j=1;j<=m&&i*prime[j]<=inf;j++)
		{
			v[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
	}
}
int get(int &a,int b)
{
	int ans=0;
	while(a%b==0)a/=b,ans++;
	return ans;
}
int a0,a1,b0,b1;
int calc(int x)
{
	int ans=0;
	int ma=get(a0,x),mb=get(b0,x),mc=get(a1,x),md=get(b1,x);
	if(ma==mc&&mb==md&&mc<=md)ans=md-mc+1;
	else if(ma>mc&&mb==md&&mc<=md)ans=1;
	else if(ma==mc&&mb<md&&mc<=md)ans=1;
	else if(ma>mc&&mb<md&&mc==md)ans=1;
	return ans;
	
}
int main()
{
	g_p();
	int n;scanf("%d",&n);
	while(n--)
	{
		int ans=1;
		scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
		for(int i=1;i<=m&&(ll)prime[i]*prime[i]<=b1;i++)
		{
			if(b1%prime[i]==0)
				ans*=calc(prime[i]);
		}
		if(b1>1)ans*=calc(b1);
		printf("%d\n",ans);
	}
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值