CF1024E maxpsum

题意

给定 (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;	
}
原文地址:https://www.cnblogs.com/VeniVidiVici/p/11741034.html