【YBT2022寒假Day5 A】序列计数(组合数)(莫队)


序列计数

题目链接:YBT2022寒假Day5 A

题目大意

多组询问,每次给你 l,r,x,问你有多少个序列满足序列长度 m 在 l,r 之间,且序列是一个单调上升序列,最小值大于等于 1,最大值小于等于 x。

思路

我们其实会发现它这个问题就是求 \(\sum\limits_{i=l}^rC_x^i\)
(毕竟它就相当于你在 \(1\sim x\) 中选 \(l\sim r\) 个数,然后排序一下就是一个方案)

然后这个我们先前缀和:\(\sum\limits_{i=1}^rC_{x}^i-\sum\limits_{i-1}^{l-1}C_{x}^i\)
然后问题就变成了求 \(G_x^i=\sum\limits_{i=1}^yC_x^i\)

然后这个感觉就很像可以离线做的那种。
然后你会想到莫队,试着看看它能不能搞。
然后你就会发现这两个东西:
\(G_{x}^y=G_{x}^{y-1}+C_x^y\)(这个显然)
\(G_x^y=2G_{x-1}^y-C_{x-1}^y\)(大概就是你把 \(G_x^y\) 里面的每个 \(C_x^i\) 都拆成 \(C_{x-1}^i+C_{x-1}^{i-1}\)

然后你就可以用莫队搞了。

代码

#include
#include
#include
#define ll long long
#define mo 998244353

using namespace std;

struct node {
	int l, r, x;
}q[200001];
struct Ask {
	int n, m, pl, op;
}qq[400001];
int T, tot, K;

ll jc[200001], inv[200001], now, inv2;
ll ans[200001];

bool cmp(Ask x, Ask y) {
	return ((x.n - 1) / K == (y.n - 1) / K) ? x.m < y.m : x.n < y.n;
}

ll C(ll n, ll m) {
	return jc[n] * inv[m] % mo * inv[n - m] % mo;
}

int main() {
//	freopen("sequence.in", "r", stdin);
//	freopen("sequence.out", "w", stdout);
	
	scanf("%d", &T);
	for (int i = 1; i <= T; i++) {
		scanf("%d %d %d", &q[i].l, &q[i].r, &q[i].x);
		qq[++tot] = (Ask){q[i].x, min(q[i].x, q[i].r), i, 1};
		qq[++tot] = (Ask){q[i].x, min(q[i].x, q[i].l - 1), i, mo - 1};
	}
	
	jc[0] = 1; for (int i = 1; i <= 200000; i++) jc[i] = jc[i - 1] * i % mo;
	inv[0] = inv[1] = 1; for (int i = 2; i <= 200000; i++) inv[i] = inv[mo % i] * (mo - mo / i) % mo;
	inv2 = inv[2]; for (int i = 1; i <= 200000; i++) inv[i] = inv[i - 1] * inv[i] % mo;
	
	K = 491;
	sort(qq + 1, qq + tot + 1, cmp);
	int L = 1, R = 0; now = 1;
	for (int i = 1; i <= tot; i++) {
		while (L < qq[i].n) now = (now * 2 - C(L, R) + mo) % mo, L++;
		while (L > qq[i].n) L--, now = (now + C(L, R)) * inv2 % mo;
		while (R < qq[i].m) now = (now + C(L, R + 1)) % mo, R++;
		while (R > qq[i].m) R--, now = (now - C(L, R + 1) + mo) % mo;
		ans[qq[i].pl] = (ans[qq[i].pl] + now * qq[i].op % mo) % mo;
	}
	
	for (int i = 1; i <= T; i++) printf("%lld\n", ans[i]);
	
	return 0;
}