题意:定义合法数组\(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\)。

引入第三个条件后,答案为

 

\[\begin{aligned} &\sum_{a_1=l_1}^{r_1}\sum_{a_2=l_2}^{r_2}\cdots\sum_{a_n=l_n}^{r_n}[\sum_{i=1}^{n}a_i\le m][gcd(a_1,a_2,...,a_n)=1]\\ =&\sum_{a_1=l_1}^{r_1}\sum_{a_2=l_2}^{r_2}\cdots\sum_{a_n=l_n}^{r_n}[\sum_{i=1}^{n}a_i\le m]\sum_{d|gcd(a_1,a_2,...,a_n)}\mu(d)\\ =&\sum_{a_1=l_1}^{r_1}\sum_{a_2=l_2}^{r_2}\cdots\sum_{a_n=l_n}^{r_n}[\sum_{i=1}^{n}a_i\le m]\sum_{d|a_1\&d|a_2\cdots\&d|a_n}\mu(d)\\ =&\sum_{d=1}^{m}\mu(d)\sum_{a_1=\lceil\frac{l_1}{d}\rceil}^{\lfloor\frac{r_1}{d}\rfloor}\sum_{a_2=\lceil\frac{l_2}{d}\rceil}^{\lfloor\frac{r_2}{d}\rfloor}\cdots\sum_{a_n=\lceil\frac{l_n}{d}\rceil}^{\lfloor\frac{r_n}{d}\rfloor}[\sum_{i=1}^{n}a_id\le m] \end{aligned} \]

 

第二个和式及其之后的和式背包即可,总时间复杂度\(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);
}