CF1499D The Number of Pairs

洛谷题面

题目大意

\(T\) 组询问,每组询问给定三个整数 \(c,d,x\)

问有多少对 \((a,b)\) 使得 \(c\times \operatorname{lcm}(a,b) - d\times \gcd(a , b) = x\)

\(c,d,x\le 10^7\)

题目分析

直接枚举复杂度直接爆炸,考虑化式子:

\[\operatorname{lcm}(a,b)=\dfrac{x+d\times \gcd(a,b)}{c} \]

显然 \(\operatorname{lcm}(a,b)\) 一定为 \(\gcd(a,b)\),所以不妨设 \(\operatorname{lcm}(a,b)=r\times \gcd(a,b)\)

于是有:

\[r\times \gcd(a,b)=\dfrac{x+d\times\gcd(a,b)}{c} \]

\[r=\dfrac{\frac{x}{\gcd(a,b)}+d}{c} \]

\[r\times c-d=\dfrac{x}{\gcd(a,b)} \]

所以有:

\[\gcd(a,b)=\dfrac{x}{r\times c-d} \]


\(\gcd(a,b)\) 一定是正整数,所以 \((r\times c-d)|x\)

\(c,d,x\) 已给出,枚举 \(r\) 即可。

\(c,d,x\) 的数据范围都很大,为 \(1e7\),可以想到什么?

马上想到埃氏筛/欧拉筛。

欧拉筛时,我们还可以顺便处理出 \(sum_i\),表示 \(i\) 的质因子个数。

\(i\) 是质数,则 \(sum_i\) 一定为 \(1\)

其他情况正常判断即可。


考虑一下:现在知道 \(i\)\(x\) 的一个因数,我们可以干什么?

\(i\) 能被表示成 \(r\times c-d\) 的形式,那么此时方案数为 \(2^{sum_r}\);否则为 \(0\)

其中,\(r\gets \dfrac{d+i}{c}\)

还要考虑一点:若当前枚举的 \(r\) 的平方并不等于 \(x\),则再加上 \(\dfrac{x}{i}\) 对答案的贡献。

可以让这一步的时间复杂度变为 \(O(\sqrt{x})\)

于是这道题就做完了。

代码

虽然码风比较奇怪,但是感觉思路比较清晰qwq。

const int ma=2e7+5;

int p[ma],sum[ma];//sum[i]:i 的质因子个数 

bool is[ma];

int T,c,d,x;

int idx;

inline void init(int R)
{
	is[1]=true;
	
	for(register int i=2;i<R;i++)
	{
		if(is[i]==false)
		{
			p[++idx]=i;
			
			sum[i]=1;
		}
		
		for(register int j=1;j<=idx && i*p[j]<R;j++)
		{
			is[i*p[j]]=true;
			
			sum[i*p[j]]=sum[i]+1;
			
			if(i%p[j]==0)
			{
				sum[i*p[j]]=sum[i];
				
				break;
			}
		}
	}
}

inline int calc(int now)
{
	if((d+now)%c!=0)
	{
		return 0;
	}
	
	int r=(d+now)/c;
	
	return 1ll<<sum[r];
}

#undef int

int main(void)
{
	#define int long long
	
	init(ma);
	
	T=read();
	
	while(T--)
	{
		c=read(),d=read(),x=read();
		
		int ans(0);
		
		for(register int i=1;i*i<=x;i++)
		{
			if(x%i==0)
			{
				ans+=calc(i);
				
				if(i*i!=x)
				{
					ans+=calc(x/i);
				}
			}
		}
		
		printf("%lld\n",ans);
	}
	
	return 0;
}
posted @ 2021-12-15 22:48  Coros_Trusds  阅读(24)  评论(0编辑  收藏  举报