题目描述:
题意:
给定一个长度为 n(n≤2∗105) 的数组 a ,问有多少种长度为 n 的数组 b 满足
- 1 ≤ b[i] ≤ m(m≤109)
- 对于任意的 i ,满足 gcd(b[1],b[2],b[3]...b[i])=a[i]
首先 gcd 操作是递减的, gcd(b[1],b[2],b[3]...b[i])≥gcd(b[1],b[2],b[3]...b[i],b[i+1])
也就是需要满足 a[i−1]≥a[i]
且有 b[1]=a[1]
gcd(b[1],b[2],b[3]...b[i−1])=a[i−1]
gcd(b[1],b[2],b[3]...b[i−1],b[i])=a[i]
着我们有 gcd(a[i−1],b[i])=a[i] 也就是 a[i−1]=k∗a[i] (就是 a[i] 是 a[i−1] 的一个因子
所以 a[i−1]%a[i]=0
这样 a 的合法条件就讨论完了。( a[i−1]%a[i]≠0 就包含了 a[i−1]<a[i] 这个信息)
考虑每个 b[i] 的可能。
由 gcd(a[i−1],b[i])=a[i] 得, b[i] 是 a[i] 的倍数。
a[i−1]=k1∗a[i],b[i]=k2∗a[i] 且 gcd(k1,k2)=1
也就是 k2∈[1,m/a[i]] 且 k2 与 a[i−1] / a[i] 互质。
那么问题就变成了,区间互质问题。我们需要容斥来解决
问题是, n=2∗105 ,用容斥的复杂度是 m 啊。
但是我们注意到, a[i] 是 a[i−1] 的因子,也就是说如果 a[i]≠a[i−1] 的情况下。
a[i]≤a[i−1]2 ,是logn级别的递减,所以我们记忆下 (m/a[i],a[i−1]/a[i]) 即可
模板:
vector<int>prime;
int num = 0;
int sum = 0;
void pr(int n) {
prime.clear();
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
prime.push_back(i);
while (n % i == 0)n /= i;
}
}
if (n > 1)prime.push_back(n);
}
void dfs(int pos, int mul, int len) {
if (pos == prime.size()) {
if (len) {
if (len % 2)sum += num / mul;
else sum -= num / mul;
}
return;
}
dfs(pos + 1, mul, len);
dfs(pos + 1, mul * prime[pos], len + 1);
}
map<pair<int,int>, int>mp;//记忆化
int que(int L, int k) {
if (mp.count({ L,k }))return mp[{L, k}];
pr(k);
num = L; sum = 0;
dfs(0, 1, 0);
return mp[{L, k}] = (L - sum);
}
const int N = 2e5 + 5;
int n, a[N], m;
const int mod = 998244353;
void slove() {
cin >> n >> m;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 2; i <= n; i++) {
if (a[i - 1] % a[i]) {
cout << 0 << endl;
return;
}
}
ll ans = 1;
for (int i = 2; i <= n; i++) {
ans *= que(m / a[i], a[i - 1] / a[i]);
ans %= mod;
}
cout << ans << endl;
}