0%

2026 杭电暑期多校 8-1003-太近就不合法了

题目大意

太近就不合法了

时间限制:3000 MS (Others) / 6000 MS (Java)

内存限制:524288 KB (Others) / 524288 KB (Java)

nn 个依次排列的位置,编号为 1,2,,n1, 2, \ldots, n

每次询问给出两个整数 x,kx, k。你需要选择若干位置,满足以下两个条件:

  1. 位置 xx 不能被选择。

  2. 任意两个被选择的位置的编号之差的绝对值不小于 kk

每次询问相互独立。请你求出每次询问的合法选择方案数。注意,允许不选择任何位置。由于答案可能很大,请将结果对 998244353998244353 取模后输出。

第一行包含一个整数 TT,表示测试数据的组数。

对于每组测试数据:

第一行包含两个整数 n,qn, q,分别表示位置的数量和询问的数量。

接下来 qq 行,每行包含两个整数 xi,kix_i, k_i,表示一次询问。

数据范围与约定

  • T=104T = 10^4

  • 1n,q1051 \le n, q \le 10^5

  • 1xi,kin1 \le x_i, k_i \le n

  • n=106\sum n = 10^6

  • q=106\sum q = 10^6

对于每次询问,输出一行一个整数,表示合法的选择方案数对 998244353998244353 取模后的结果。

Plaintext

1
2
3
4
5
6
7
8
9
10
3
5 2
3 2
4 3
1 2
1 1
1 1
3 2
2 1
1 3

Plaintext

1
2
3
4
5
6
9
7
1
1
4
3

第一组测试数据

  • 共有 55 个位置,即 {1,2,3,4,5}\{1, 2, 3, 4, 5\}

  • 第一次询问x=3,k=2x=3, k=2):不能选择位置 33,且相邻选择的位置距离至少为 22。合法的方案有 99 种,分别为:空集 \emptyset, {1}\{1\}, {2}\{2\}, {4}\{4\}, {5}\{5\}, {1,4}\{1, 4\}, {1,5}\{1, 5\}, {2,4}\{2, 4\}, {2,5}\{2, 5\}

  • 第二次询问x=4,k=3x=4, k=3):不能选择位置 44,且相邻选择的位置距离至少为 33。合法的方案有 77 种,分别为:空集 \emptyset, {1}\{1\}, {2}\{2\}, {3}\{3\}, {5}\{5\}, {1,5}\{1, 5\}, {2,5}\{2, 5\}(注意 {1,4}\{1, 4\} 不合法因为包含了 44)。

第二组测试数据

  • 只有 11 个位置,即 {1}\{1\}

  • 两次询问均为 x=1,k=1x=1, k=1,不能选择位置 11。唯一合法的方案是不选择任何位置,即空集 \emptyset,方案数为 11

第三组测试数据

  • 共有 33 个位置,即 {1,2,3}\{1, 2, 3\}

  • 第一次询问x=2,k=1x=2, k=1):不能选择位置 22,相邻位置距离至少为 11。合法方案有 44 种:\emptyset, {1}\{1\}, {3}\{3\}, {1,3}\{1, 3\}

  • 第二次询问x=1,k=3x=1, k=3):不能选择位置 11,相邻位置距离至少为 33。合法方案有 33 种:\emptyset, {2}\{2\}, {3}\{3\}

思路讲解

image

image

image

image

下面的这个组合式子,可以比较简单的使用这个映射来证明啊。

f(m,k)=c=0m+k1k(m(c1)(k1)c)f(m, k) = \sum_{c=0}^{\lfloor \frac{m+k-1}{k} \rfloor} \binom{m - (c-1)(k-1)}{c}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
constexpr ll SQRT = 200;

ll f_cal(ll m, ll k) {
ll ans = 0;
ll up = (m + k - 1) / k;
for (int c = 0; c <= up; ++c) {
ans += CC(m - (c - 1) * (k - 1), c);
ans %= mod;
}
ans %= mod;
if (ans < 0) ans += mod;
return ans;
}

void Solve() {
Cin(N, Q);
map<ll, vector<ll> > mp;
vector<vector<ll> > F(N + 2, vector<ll>(min(N, SQRT) + 2));

for (int k = 1; k <= min(N, SQRT); ++k) {
F[0][k] = 1;
for (int i = 1; i <= N; ++i) {
F[i][k] = F[i - 1][k] + (i - k < 0 ? 1 : F[i - k][k]);
F[i][k] %= mod;
}
}
for (int _ = 1; _ <= Q; ++_) {
ll x, k;
Cin(x, k);
ll up = (N + k - 1) / k;
if (k > SQRT) {
// 这个的计算是 k 越小,计算的越多的啊。
ll ans = f_cal(N, k) - (x - k < 0 ? 1 : f_cal(x - k, k)) * (
N - x - k + 1 < 0 ? 1 : f_cal(N - x - k + 1, k));
ans %= mod;
if (ans < 0) ans += mod;
write(ans);
putc('\n');
} else {
// 因此我们把这个 k 比较小的这个直接用数组存起来,后面直接输出即可
ll ans = 0;
ans = F[N][k] - (x - k < 0 ? 1 : F[x - k][k]) * (N - x - k + 1 < 0 ? 1 : F[N - x - k + 1][k]);
ans %= mod;
if (ans < 0) ans += mod;
write(ans);
putc('\n');
}
}
}

AC代码

AC
https://acm.hdu.edu.cn/contest/view-code?cid=1236&rid=7030

心路历程(WA,TLE,MLE……)