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;
}