1. 程式人生 > 其它 >CF1499D The Number of Pairs

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