codefoces E - Mocha and Stars (容斥)
题目链接:http://codeforces.com/contest/1559/problem/E
先不考虑 \(gcd\) 的限制,设 \(dp[i][j]\) 表示前 \(i\) 个数和为 \(j\) 的方案数
容斥掉 \(gcd\) 不为 \(1\) 的答案,那就是考虑只选 \(gcd\) 的倍数的数的答案,容斥系数是莫比乌斯函数
时间复杂度 \(O(nmln(m))\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxm = 100010;
const int maxn = 55;
const int M = 998244353;
int n, m, cnt = 0;
int a[maxm * 2], l[maxm][maxn], r[maxm][maxn];
int dp[maxn][maxm], f[maxm], sum[maxn][maxm];
int prime[maxm], is_prime[maxm], mu[maxm];
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
mu[1] = 1;
for(int i = 2; i <= 100000; ++i){
if(!is_prime[i]){
prime[++cnt] = i;
mu[i] = -1;
}
for(int j = 1 ; j <= cnt && prime[j] * i <= 100000 ; ++j){
is_prime[i * prime[j]] = 1;
if(i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
} else {
mu[i * prime[j]] = -mu[i];
}
}
}
n = read(), m = read();
for(int i = 1 ; i <= n ; ++i) l[1][i] = read(), r[1][i] = read();
memset(f, 0, sizeof(f));
for(int g = 2 ; g <= m ; ++g){
int tot = 0;
for(int i = 0 ; i <= m ; i += g){
a[++tot] = i;
}
for(int i = 1 ; i <= n ; ++i){
int p = lower_bound(a + 1, a + 1 + tot, l[1][i]) - a;
if(p == tot + 1) p = tot;
l[g][i] = a[p];
p = lower_bound(a + 1, a + 1 + tot, r[1][i]) - a;
if(p == tot + 1) p = tot;
r[g][i] = a[p];
if(r[g][i] > r[1][i]) r[g][i] -= g;
}
}
int res = 0;
for(int g = 1 ; g <= m ; ++g) { // gcd
int tmp = g;
int cnt_fac = 0;
int mx = 0; int up = (int)sqrt(g+0.5);
for(int j = 1 ; j <= cnt && prime[j] <= up ; ++j){
if(tmp % prime[j] == 0) ++cnt_fac;
int cnt_p = 0;
while(tmp % prime[j] == 0){
tmp /= prime[j];
++cnt_p;
}
mx = max(mx, cnt_p);
}
if(tmp > 1) ++cnt_fac, mx = max(mx, 1);
for(int i = 1 ; i <= n ; ++i){
for(int j = g ; j <= m ; j += g) dp[n][j] = 0;
}
dp[0][0] = 1;
sum[0][1] = 1; int down = 0;
for(int i = g ; i <= m ; i += g) sum[0][i+1] = sum[0][i-g+1];
for(int i = 1 ; i <= n ; ++i){
down += l[g][i];
if(l[g][i] > r[g][i]) continue;
for(int j = g ; j <= m ; j += g){
dp[i][j] = ((sum[i-1][max(0, j-l[g][i]+1)] - sum[i-1][max(0, j-r[g][i]-g+1)]) % M + M) % M;
sum[i][j+1] = (sum[i][j-g+1] + dp[i][j]) % M;
}
}
for(int i = g ; i <= m ; i += g) {
f[g] = (f[g] + dp[n][i]) % M;
}
res = ((res + mu[g] * f[g]) % M + M) % M;
}
printf("%d\n", res);
return 0;
}