CF1334E题解
题解思路:
我们看看他有什么性质:
若我们去掉一个数的质因子,那么他就会向下走一格。
还有一个,我们看一下样例:
12 到2 那么我们先去掉一个质因子3 ,再去掉一个质因子2 ,或先取掉质因子2 ,再去掉一个质因子3 ,那么他们的路径权值是一样的。证明:假设
u 能走向v ,并u > v ,因为若从u 走向v ,那么把他质因子分解,既然u 能走向v ,那么v 一定是u 的某个因子的因子。所以v 一定是u 的因子,因为u 是在不断去掉质因子才达到v 的。我们先把
u 质因子分解:u = p_1^{a_1} p_2^{a_2} p_3^{a_3} ...\ p_m^{a_m} ,那么你走下去,那么你会去掉一些质因子,就是a_1-x_1,a_2-x_2 ...\ a_m-x_m ,有的可能是去掉了零个,那么他的因子数为(a_1+1)(a_2+1)...(a_m+1) ,所以u 的因子数为(a_1+1)(a_2+1)...(a_m+1) ,而v 的因子数为(a_1-x_1+1)(a_1-x_2+1)...(a_m-x_m+1) ,那么我们把u 设为x ,那么假设我们先去掉p_i 的一个因子,就相当去掉一个\frac{\mathrm{x}}{\mathrm{a_i}} ,下一个我们去掉一个p_k 就相当于去掉:\frac{\mathrm{xa_i}}{\mathrm{(a_i+1)(a_j + 1)}}+\frac{\mathrm{x}}{\mathrm{a_i+1}} ,想乘得\frac{\mathrm{a_i+a_j+1}}{\mathrm{(a_i+1)(a_j+1)}}x ,那么a_i 和a_j 交换了位置,那么其实不变,在推广到普通情况,也是相同的,证毕。
那么我们从
然后若
那么我们怎么算呢,因为他的质因子为
那么我们求一下他们的全排列,但有重复的情况,比如全是相同的数,所以他的全排列有很多种,但都是一样的。
AC CODE:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
const int mod = 998244353;
ll D , fac[60] , inv[60];
vector <pair <ll , int>> p;
map <ll , vector<int>>mp;//就相当于质因数分解的系数
vector <int> now;
ll gcd (ll a , ll b) {return b == 0 ? a : gcd (b , a % b);}//求最大公因数
ll power (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 dfs (int dep , ll sum) {//暴力构造O(sqrt(n))
if (dep == p.size()) {
mp[sum] = now;//取出来,放到一个map里
return;
}
auto x = p[dep];
now.push_back (0);
dfs (dep + 1 , sum);
now.pop_back();
for (int i = 1; i <= x.second; ++ i) {
sum *= x.first;
now.push_back (i);
dfs (dep + 1 , sum);
now.pop_back ();
}
}
void init () {//预处理函数
fac[0] = fac[1] = 1;
for (int i = 2; i <= 59; ++ i)
fac[i] = fac[i - 1] * i % mod;//预处理阶乘
for (int i = 1; i <= 59; ++ i)
inv[i] = power (fac[i] , mod - 2);//逆元因为mod是质数,所以可以预处理
ll d = D;
for (ll i = 2; i <= d / i; ++ i) {//分解质因数.
if (d % i == 0) {
int cnt = 0;
while (d % i == 0) {
d /= i;
++ cnt;
}
p.push_back ({i , cnt});
}
}
if (d > 1) p.push_back ({d , 1});
dfs (0 , 1);//构造
}
int main() {
cin >> D;
init();//预处理
int q;
cin >> q;
while (q --){
ll u , v;
cin >> u >> v;
ll x = gcd (u , v);
vector <int> a , b , c;//把每个数的系数取出来
a = mp[u] , b = mp[v] , c = mp[x];
for (int i = 0; i < a.size(); ++ i) {//做差,得出来的数就是答案的系数
a[i] -= c[i];
b[i] -= c[i];
}
ll sum = 0 , sum2 = 0 , ans = 1 , ans2 = 1;
for (auto x : a) {//计算
if (!x) continue;
sum += x;
ans = ans * inv[x] % mod;
}
ans = ans * fac[sum] % mod;
for (auto x : b) {//计算
if (!x) continue;
sum2 += x;
ans2 = ans2 * inv[x] % mod;
}
ans2 = ans2 * fac[sum2] % mod;
ans = ans * ans2 % mod;//最后相乘。
cout << ans << endl;
}
return 0;
}