Address
Solution
- 尝试简化第三个限制,设 k = ⌊ n − 1 2 ⌋ k = \lfloor \dfrac{n - 1}{2}\rfloor k=⌊2n−1⌋,我们取前 k + 1 k + 1 k+1 个数作为第一个集合,取后 k k k 个数作为第二个集合,因为这两个集合的差是所有选集合的方案中最小的,所以只要这两个集合满足条件,所有的集合都能满足条件。
Algorithm 1
-
因为 n n n 的奇偶性会影响中间是否会多出一个数,我们分情况讨论:
-
若 n n n 是偶数,枚举第 k + 2 k + 2 k+2 个数为 x x x,那么对剩下的数有如下要求:
- x x x 与前 k + 1 k + 1 k+1 个数的差 ∈ [ 0 , x ) \in [0,x) ∈[0,x) 且差递减;
- 后 k k k 个数与 x x x 的差 ∈ [ 0 , n − x ] \in [0,n-x] ∈[0,n−x] 且差递增;
- x x x 与前 k + 1 k + 1 k+1 个数的差的和加上后 k k k 个数与 x x x 的差的和小于 x x x。
设 f i , j f_{i,j} fi,j 表示已经确定了前 i i i 个数、 x x x 与这些数的差的和为 j j j 的方案数。
转移即从大到小枚举差 l ( l ∈ [ 0 , n ) ) l(l \in [0,n)) l(l∈[0,n)),令 f i + 1 , j + l = f i + 1 , j + l + f i , j f_{i + 1,j + l} = f_{i + 1,j + l} + f_{i,j} fi+1,j+l=fi+1,j+l+fi,j。
由于第二维 j ≤ n j \le n j≤n,存在合法方案时一定有 i l ≤ n il \le n il≤n,时间复杂度 O ( n 2 ln n ) \mathcal O(n^2 \ln n) O(n2lnn)。
后 k k k 个数的方案可以看做是选取若干个后缀区间
+1
,设 g i , j g_{i,j} gi,j 表示已经选了 i i i 个后缀、这些后缀的长度之和为 j j j 的方案数。转移即从大到小枚举后缀长度 l ( l ∈ [ 0 , k ] ) l(l \in [0,k]) l(l∈[0,k]),令 g i + 1 , j + l = g i + 1 , j + l + g i , j g_{i + 1,j + l} = g_{i + 1,j + l} + g_{i,j} gi+1,j+l=gi+1,j+l+gi,j,时间复杂度同样是 O ( n 2 ln n ) \mathcal O(n^2 \ln n) O(n2lnn)。
最后的答案即为:
∑ x = 1 n ∑ i = 0 x − 1 f k + 1 , i ∑ j = 0 x − i − 1 g n − x , j \begin{aligned}\sum \limits_{x = 1}^{n} \sum \limits_{i = 0}^{x - 1} f_{k + 1,i} \sum \limits_{j = 0}^{x - i - 1}g_{n-x,j}\end{aligned} x=1∑ni=0∑x−1fk+1,ij=0∑x−i−1gn−x,j
预处理 g g g 第二维的前缀和即可 O ( n 2 ) \mathcal O(n^2) O(n2) 计算。 -
若 n n n 是奇数,枚举第 k + 1 k + 1 k+1 个数为 x x x,只要最后算答案时把 f k + 1 , i f_{k+1,i} fk+1,i 改为 f k , i f_{k,i} fk,i,其它部分与偶数的情况完全相同。
-
-
总的时间复杂度 O ( n 2 ln n ) \mathcal O(n^2 \ln n) O(n2lnn)。
Code 1
#include <bits/stdc++.h>
const int N = 5005;
int f[N][N], g[N][N];
int n, ans, mod;
inline void add(int &x, int y)
{
x += y;
x >= mod ? x -= mod : 0;
}
int main()
{
scanf("%d%d", &n, &mod);
int k = n - 1 >> 1;
f[0][0] = g[0][0] = 1;
for (int c = n - 1; c >= 0; --c)
for (int i = 0, im = !c ? n : n / c; i <= im; ++i)
for (int j = 0; j <= n - c; ++j)
add(f[i + 1][j + c], f[i][j]);
for (int c = k; c >= 0; --c)
for (int i = 0, im = !c ? n : n / c; i <= im; ++i)
for (int j = 0; j <= n - c; ++j)
add(g[i + 1][j + c], g[i][j]);
for (int i = 0; i <= n; ++i)
for (int j = 1; j <= n; ++j)
add(g[i][j], g[i][j - 1]);
if (!(n & 1))
{
for (int x = 1; x <= n; ++x)
for (int j = 0; j < x; ++j)
ans = (1ll * f[k + 1][j] * g[n - x][x - j - 1] + ans) % mod;
}
else
{
for (int x = 1; x <= n; ++x)
for (int j = 0; j < x; ++j)
ans = (1ll * f[k][j] * g[n - x][x - j - 1] + ans) % mod;
}
printf("%d\n", ans);
return 0;
}
Algorithm 2
-
考虑将 A A A 数组差分,去掉单调性的限制,令差分数组为 B B B。
-
令 B 0 = 1 B_0 = 1 B0=1,则 A i = 1 + ∑ j = 1 i B j A_i = 1 + \sum \limits_{j = 1}^{i}B_j Ai=1+j=1∑iBj,因此其中一个限制条件就是 ∑ i = 1 n B i < n \sum \limits_{i = 1}^{n} B_i < n i=1∑nBi<n。
-
同样对 n n n 的奇偶性进行讨论:
-
若 n n n 为奇数, ⌊ n − 1 2 ⌋ + 1 = n + 1 2 \lfloor \dfrac{n - 1}{2} \rfloor + 1 = \dfrac{n + 1}{2} ⌊2n−1⌋+1=2n+1,列出限制条件:
∑ i = 1 n + 1 2 A i > ∑ i = n + 1 2 + 1 n A i ∑ i = 1 n + 1 2 ( 1 + ∑ j = 1 i B j ) > ∑ i = n + 1 2 + 1 n ( 1 + ∑ j = 1 i B j ) 2 ∑ i = 1 n + 1 2 ∑ j = 1 i B j ≥ ∑ i = 1 n ∑ j = 1 i B j 2 ∑ i = 1 n + 1 2 ( n + 1 2 − i + 1 ) B i ≥ ∑ i = 1 n ( n − i + 1 ) B i \begin{aligned}\sum \limits_{i = 1}^{\frac{n + 1}{2}}A_i &> \sum \limits_{i = \frac{n + 1}{2} + 1}^{n} A_i \\\sum \limits_{i = 1}^{\frac{n + 1}{2}}(1 + \sum \limits_{j = 1}^{i}B_j) &> \sum \limits_{i = \frac{n + 1}{2} + 1}^{n}(1 + \sum \limits_{j = 1}^{i}B_j) \\2\sum \limits_{i = 1}^{\frac{n + 1}{2}}\sum \limits_{j = 1}^{i}B_j &\ge \sum \limits_{i = 1}^{n}\sum \limits_{j = 1}^{i}B_j \\2\sum \limits_{i = 1}^{\frac{n + 1}{2}}(\dfrac{n + 1}{2} - i + 1)B_i &\ge \sum \limits_{i = 1}^{n}(n - i + 1)B_i\\\end{aligned} i=1∑2n+1Aii=1∑2n+1(1+j=1∑iBj)2i=1∑2n+1j=1∑iBj2i=1∑2n+1(2n+1−i+1)Bi>i=2n+1+1∑nAi>i=2n+1+1∑n(1+j=1∑iBj)≥i=1∑nj=1∑iBj≥i=1∑n(n−i+1)Bi
简单移项后,我们可以得到:
∑ i = 1 n C i B i ≤ 0 \begin{aligned} \sum \limits_{i = 1}^{n}C_iB_i \le 0 \end{aligned} i=1∑nCiBi≤0
其中:
C i = { i − 2 1 ≤ i ≤ n + 1 2 n − i + 1 n + 1 2 < i ≤ n C_i = \begin{cases}i - 2 &1 \le i \le \dfrac{n + 1}{2} \\n - i + 1 &\dfrac{n + 1}{2} < i \le n\\\end{cases} Ci=⎩⎪⎨⎪⎧i−2n−i+11≤i≤2n+12n+1<i≤n -
若 n n n 为偶数,同样可以推出 C i C_i Ci 的表达式:
C i = { i − 2 1 ≤ i ≤ n 2 + 1 n − i + 1 n 2 + 1 < i ≤ n C_i = \begin{cases}i - 2 &1\le i \le \dfrac{n}{2} + 1\\n - i + 1 &\dfrac{n}{2} + 1 < i \le n\\\end{cases} Ci=⎩⎨⎧i−2n−i+11≤i≤2n+12n+1<i≤n
整理一下,我们有:
C i = { i − 2 1 ≤ i ≤ ⌊ n 2 ⌋ + 1 n − i + 1 ⌊ n 2 ⌋ + 1 ≤ i ≤ n C_i = \begin{cases}i - 2 &1\le i \le \lfloor \dfrac{n}{2} \rfloor + 1\\n - i + 1 &\lfloor \dfrac{n}{2} \rfloor + 1 \le i \le n\\\end{cases} Ci=⎩⎨⎧i−2n−i+11≤i≤⌊2n⌋+1⌊2n⌋+1≤i≤n
注意到只有 C 1 C_1 C1 是负数,考虑列出所有和 B 1 B_1 B1 有关的限制条件:
{ B 1 ≤ n − 1 − ∑ i = 2 n B i B 1 ≥ ∑ i = 2 n C i B i \begin{cases}B_1 \le n - 1 - \sum \limits_{i = 2}^{n}B_i \\B_1 \ge \sum \limits_{i = 2}^{n}C_i B_i \\ \end{cases} ⎩⎪⎨⎪⎧B1≤n−1−i=2∑nBiB1≥i=2∑nCiBi
在已知 B i ( 2 ≤ i ≤ n ) B_i(2 \le i \le n) Bi(2≤i≤n) 的情况下,合法的 B 1 B_1 B1 的个数为:
max { 0 , n − ∑ i = 2 n ( C i + 1 ) B i } \begin{aligned}\max\{0, n - \sum \limits_{i = 2}^{n}(C_i + 1)B_i\}\end{aligned} max{0,n−i=2∑n(Ci+1)Bi}
-
-
设 f j f_j fj 表示 ∑ i = 2 n ( C i + 1 ) B i = j \sum \limits_{i = 2}^{n}(C_i + 1)B_i = j i=2∑n(Ci+1)Bi=j 的方案数,最后的答案就为 ∑ i = 0 n − 1 ( n − j ) f j \sum \limits_{i = 0}^{n - 1}(n - j)f_j i=0∑n−1(n−j)fj。
-
显然 f j f_j fj 的转移是一个完全背包,时间复杂度 O ( n 2 ) \mathcal O(n^2) O(n2)。
Code 2
#include <bits/stdc++.h>
const int N = 1e4 + 5;
int n, mod, ans, c[N], f[N];
inline void add(int &x, int y)
{
x += y;
x >= mod ? x -= mod : 0;
}
int main()
{
scanf("%d%d", &n, &mod);
int half = n >> 1;
for (int i = 2; i <= half + 1; ++i)
c[i] = i - 1;
for (int i = half + 2; i <= n; ++i)
c[i] = n - i + 2;
f[0] = 1;
for (int i = 2; i <= n; ++i)
for (int j = c[i]; j < n; ++j)
add(f[j], f[j - c[i]]);
for (int j = 0; j < n; ++j)
ans = (1ll * (n - j) * f[j] + ans) % mod;
printf("%d\n", ans);
return 0;
}