ATR102E Stop. Otherwise... [容斥]

第一道容斥

(ans[i] = sum_{j = 0}^{min(cnt, n / 2)} (-1)^j binom{cnt}{j} binom{n - 2*j + k - 1}{k - 1})

i 为 [2, 2k]
cnt是满足x, y小于等于k 且 x + y = i 的对的种类数
后面那个组合数是除了j对 数剩下的数的取值
(sum_{t = 1}^{k} X_t = n - 2j)
(X_t)指t的出现次数

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 4005;
const double eps = 1e-9;
const long long P = 998244353;
int n, k;
long long jie[N], jv[N], inv[N], tot[N];
long long C(long long x, long long y){
	return jie[x] * jv[x - y] % P * jv[y] % P;
}

int main() {
	scanf("%d%d", &k, &n);
	jie[0] = inv[0] = jv[0] = jie[1] = inv[1] = jv[1] = 1;
	for(int i = 2; i <= n + k; ++i){
		jie[i] = jie[i - 1] * i % P; 
		inv[i] = (P - P / i) * inv[P % i] % P; 
		jv[i] = jv[i - 1] * inv[i] % P;
	}
	for(int i = 1; i <= k; ++i) ++tot[i + 1], --tot[i + k + 1];
	for(int i = 1; i <= k + k; ++i) tot[i] += tot[i - 1]; //存在另一个数y满足x + y = i的x有多少个 
	for(int i = 2; i <= k + k; ++i){
		long long cnt = ((tot[i] + 1) >> 1), ans = 0;
		for(int j = 0, d = 1; j <= cnt && j + j <= n; ++j, d = P - d){
			ans = (ans + 1ll * d * C(cnt, j) % P * C(n - (j << 1) + k - 1, k - 1) % P) % P;
		    //       d = (-1)^j          选择哪几对            剩下的数取哪些 
		}
		printf("%lld
", ans);
	}
    return 0;    
}
原文地址:https://www.cnblogs.com/hjmmm/p/10609979.html