题意
给定 (N) 个 (1) 与 (M) 个 (-1),求由这 (N+M) 个数组成的所有本质不同的序列中最大前缀和的和
其中最大前缀和 (maxpsum) 定义为 (max{sum_i})(即前缀和数组中的最大值)
解法
虽然是一个套路,但是第一个想到这种转化的人也太屌了吧。。
建立一个平面直角坐标系,其中,选择 (-1) 相当于向右移动一个单位,而 (+1) 相当于向上移动一个单位(即 (-1) 作为 (x) 轴,(+1) 作为 (y) 轴)
那么,从 ((0,0)) 开始,最终一定会走到 ((m,n))
考虑在坐标系中枚举一个 (b),这个 (b) 是直线 (l:y=x+b) 的截距
那么,如果一条从 ((0,0)) 到 ((m,n)) 的路径在某一时刻位于 (l) 的上方,那么其 (maxpsum) 一定大于 (b)
设 (f_i) 为 (maxpsum) 至少为 (i) 的序列个数,那么 (f_i) 即为从 ((0,0)) 到 ((m,n)) 并且在某一时刻位于 (l) 上方的路径条数
这个不太好计算,我们再转化一下,取 ((m,n)) 对于 (l) 的对称点 ((n-b,m+b)),用组合数计算从 ((0,0)) 到这一点的路径条数。很容易证明这里的每一条路径都唯一对应 (f_i)(取一个对称)
那么就可以用一个简单容斥求出 (maxpsum) 恰好为 (i) 的序列个数了,即 (f_i-f_{i+1})
那么最后的答案即为 (sum i imes (f_i-f_{i+1}))
代码
#include <cstdio>
#include <iostream>
using namespace std;
const int MAX_N = 2e6 + 10;
const int mod = 998244853;
int N, M;
int fac[MAX_N], Ifac[MAX_N];
int f[MAX_N];
inline int mul(int x, int y) { return 1LL * x * y % mod; }
inline void inc(int& x, int y) { (x += y) >= mod ? x -= mod : 0; }
int fsp(int x, int y = mod - 2) {
int res = 1;
for (; y; x = mul(x, x), y >>= 1) if (y & 1) res = mul(res, x);
return res;
}
void init() {
int lim = N + M;
fac[0] = 1;
for (int i = 1; i <= lim; ++i) fac[i] = mul(fac[i - 1], i);
Ifac[lim] = fsp(fac[lim]);
for (int i = lim - 1; i >= 0; --i) Ifac[i] = mul(Ifac[i + 1], i + 1);
}
int C(int n, int m) {
return mul(fac[n], mul(Ifac[m], Ifac[n - m]));
}
int calc(int n, int m) { return C(n + m, n); }
int main() {
scanf("%d%d", &N, &M);
init();
int ans = 0;
for (int i = max(1, N - M); i <= N; ++i) f[i] = calc(N - i, M + i);
for (int i = N; i >= max(1, N - M); --i) inc(ans, mul(i, (f[i] - f[i + 1] + mod) % mod));
printf("%d
", ans);
return 0;
}