思路:

设n个数,它们的最大公因子为G,最小公倍数为L,问有多少种不同的方法还原这个数列。

质因数分解
每个数ai都可以分解为质因数的乘积,即:
ai=p1ei1⋅p2ei2⋅…⋅pkeik
其中p1,p2,…,pk是质数,eij是质数pj在ai中的指数。

最大公因子G是所有ai共有的质因数的最小指数的乘积,

最小公倍数L是所有ai每个质因数的最大指数的乘积。

可以知道,L一定是G的倍数。


每个质因数都是独立的,所以可以算出每个质因数在n个位置的填写情况,然后将每个质因数情况相乘。

对于质因数p,设在最大公因子中相乘l次,在最小公倍数中相乘r次,那么每个数中,相乘次数需满足[l, r],共有cnt = r - l + 1种情况。

不考虑重叠,n个位置,有cntn中方法,

注意:在n个数中需至少出现一次p相乘l次,至少出现一次p相乘r次,才能得到G和L。

在总情况中,减去没出现过l,减去没出现r的情况,再加上l和r都没出现过的情况,得到:

cntn - (cnt-1)n - (cnt - 1)n + (cnt -2)n

其实可以发现,我们只关心cnt的大小,所以令z = y / x,计算z的每个质因子相乘的个数即可。


注意事项:

在计算结果,减的过程中会出现负的情况,加mod后再减。

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 998244353;
ll ksm(ll a, ll b) {
	ll res = 1;
	while(b) {
		if(b & 1) res = a * res % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return res;
}
void solve() {
	ll x, y, n;
	cin >> x >> y >> n;
	if(y % x) {
		cout << 0 << endl;
		return;
	}
	y /= x;
	vector<ll> v;
	int t = 0;
	for(int i = 2; i <= sqrt(y) && y != 1; i++) {
		if(y % i) {
			continue;
		}
		while(y % i == 0) {
			t++;
			y /= i;
		}
		if(t) v.push_back(t);
		t = 0;
	}
	if(y != 1) v.push_back(1);
	ll ans = 1;
	for(auto e:v) {
		ll t = ksm(e + 1, n);
		if(t > 1) {
			t = (t - ksm(e, n) + mod) % mod;
			t = (t - ksm(e, n) + mod) % mod;
			t = (t + ksm(e - 1, n)) % mod;
		}
		ans = ans * t % mod;
	}
	cout << ans << endl;
}
int main() {
	int T;
	cin >> T;
	while(T--) solve();
	return 0;
}


点赞(0)
 

0.0分

0 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论