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;
}
posted @ 2021-08-20 02:16  Tartarus_li  阅读(31)  评论(0编辑  收藏  举报