题意:定义合法数组\(a=(a_1,a_2,...,a_n)\)为满足\(a_i\in[l_i,r_i]\)且\(\sum_{i=1}^{n}a_i\le m\),\(gcd(a_1,a_2,...,a_n)=1\)的数组。
求这样的合法数组个数。答案对998244353取模。\(2\le n\le 50, m \le 1e5\)
sol:去掉gcd的限制,就是一个\(O(nm)\)的背包问题。设\(f[i][j]\)为以\(j\)的容量装下前\(i\)个的方案,那么\(f[i][j] = \sum_{k=l[i]}^{r[i]}f[i-1][j-k]\),后面是一个长为\((r[i]-l[i]+1)\)的和,可以用前缀和优化,边界为\(f[0][i] = 1\)。
引入第三个条件后,答案为
第二个和式及其之后的和式背包即可,总时间复杂度\(O(mn\ln m)\)。
// Problem: E. Mocha and Stars
// Contest: Codeforces - Codeforces Round #738 (Div. 2)
// URL: https://codeforces.com/contest/1559/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7, md = 998244353;
int n, m, l[maxn], r[maxn], mu[maxn], tot, pri[maxn];
bool isp[maxn];
int ans;
void sieve() {
memset(isp, true, sizeof(isp));
isp[1] = false;
mu[1] = 1;
for (int i = 2; i <= 100000; i++) {
if (isp[i]) {
pri[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && i * pri[j] <= 100000; j++) {
isp[i * pri[j]] = false;
if (i % pri[j] == 0) {
mu[i * pri[j]] = 0;
break;
}
mu[i * pri[j]] = -mu[i];
}
}
}
int f[51][maxn], sum[51][maxn];
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d %d", &l[i], &r[i]);
}
sieve();
for (int d = 1; d <= m; d++) {
if (mu[d] == 0) continue;
int cur = m / d;
for (int i = 0; i <= cur; i++)
sum[0][i] = 1;
for (int i = 1; i <= n; i++) {
int L = (l[i]-1)/d+1, R = r[i]/d;
for (int j = L; j <= cur; j++) {
f[i][j] = sum[i-1][j-L];
if (j >= R+1)
f[i][j] = (f[i][j] - sum[i-1][j-R-1] + md) % md;
}
for (int j = 1; j <= cur; j++)
sum[i][j] = (sum[i][j-1] + f[i][j])%md;
}
ans = (ans + sum[n][cur] * mu[d]) % md;
if (ans < 0)
ans = (ans + md) % md;
}
printf("%d", ans);
}