题解:P10580 [蓝桥杯 2024 国 A] gcd 与 lcm
P10580 题解
题面
前置知识
容斥原理
(1) 集合 \(S\) 中不具有性质 \(P_1,P_2,\cdots,P_n\) 的对象个数为
\(\begin{aligned}|\overline{A_1}\cap\overline{A_2}\cap\cdots\cap\overline{A_n}|&=|S|-\sum_{i=1}^n|A_i|+\sum_{i=1}^n\sum_{j>i}|A_i\cap A_j|-\sum_{i=1}^n\sum_{j>i}\sum_{k>j}|A_i\cap A_j\cap A_k|\\&+\cdots+(-1)^{n-1}|A_1\cap A_2\cap \cdots\cap A_n|\end{aligned}\)
简记(我的方法):奇减偶加
(2) 集合 \(S\) 中至少具有性质 \(P_1,P_2,\cdots,P_n\) 之一的对象个数为
\(\begin{aligned}|A_1\cup A_2\cup\cdots\cup A_n|&=\sum_{i=1}^n|A_i|-\sum_{i=1}^n\sum_{j>i}|A_i\cap A_j|+\sum_{i=1}^n\sum_{j>i}\sum_{k>j}|A_i\cap A_j\cap A_k|+\cdots\\&+(-1)^{n-1}|A_1\cap A_2\cap \cdots\cap A_n|\end{aligned}\)
简记:奇加偶减
思路
首先,显然 \(a\) 肯定都是 \(x\) 的倍数,问题就是在 \(\frac{y}{x}\) 上。
我们可以将 \(\frac{y}{x}\) 质因数后一个个考虑,设 \(\begin{aligned}\frac{y}{x}=\sum_{i=1}p_i^{e_i}\end{aligned}\),对于每一个质数分开去考虑,最后把答案乘起来(乘法原理),不妨把最小公倍数是 \(x\) 和最大公倍数是 \(y\) 看做两个条件,然后去容斥。
对于一个质数 \(p_i\) 我们有。
发现算最大公因数是 \(x\),最小公倍数是 \(y\) 的方案数是比较困难的,所以我们不妨把题目转化为集合 \(S\) 中不具有性质 \(P_1,P_2\) 的对象个数有多少,其中:
- \(P_1\) 为最大公约数不为 \(x\)。
- \(P_2\) 为最小公倍数不为 \(y\)。
于是有。
- 没有 \(P_1,P_2\) 的限制,我们可以取到 \([0,e_i]\),所以 \(|S|=(e_i+1)^n\) 。
- 只有 \(P_1\) 的限制,我们可以取到 \([1,e_i]\)(取到 \(0\) 最大公因数就是 \(x\) 了),所以 \(|A_1|=e_i^n\)。
- 只有 \(P_2\) 的限制,我们可以取到 \([0,e_i-1]\)(取到 \(e_i\) 最小公倍数就是 \(y\) 了),所以 \(|A_2|=e_i^n\)。
- 对于有 \(P_1,P_2\) 的限制,我们只能取到 \([1,e_i-1]\),所以 \(|A_1\cap A_2|=(e_i-1)^n\)。
故,一个质数的方案数为 \(|S|-|A_1|-|A_2|+|A_1\cap A_2|=(e_i+1)^n-2\times e_i^n+(e_i-1)^n\)。
最后把每个质数的方案数乘起来即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int mod=998244353;
ll x,y,n,t,ans;
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
ll ksm(ll a, ll b){ll res=1;while(b){if(b&1)res=res*a%mod;a=a*a%mod;b>>=1;}return res;}
void solve(){
x=read();y=read();n=read();t=y/x;ans=1;
for(int i=2; i<=sqrt(t); i++) if(t%i==0){
ll num=0;
while(t%i==0) t/=i,num++;
ans=ans*((ksm(num+1,n)-(2*ksm(num,n)%mod)+ksm(num-1,n))%mod+mod)%mod;
}
if(t>1){ans=ans*((ksm(2,n)-2)%mod+mod)%mod;}
write(ans);putchar('\n');
}
int main(){
ll T=read();while(T--)solve();
return 0;
}