【SSLOJ1481】最大前缀和

题目

思路

将每一个 \(1\)\(-1\) 看成向上和向右,那么就转换成从 \((0,0)\)\((n,m)\) 的方案数。
枚举答案 \(i\),那么显然这条路径不能与 \(y=x+i+1\) 相交。那么答案不超过 \(i\) 的方案数就是从 \((0,0)\)\((n,m)\) 的方案数减去 \((0,0)\) 关于直线对称的点到 \(n,m\) 的方案数。即为

\[C^{n}_{n+m}-C^{m+i+1}_{n+m} \]

注意答案为 \(i\) 的方案数为这个数减去答案不超过 \(i-1\) 的方案数。
预处理阶乘和逆元即可。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=2000010,MOD=998244853;
ll ans,pre,fac[N],inv[N];
int n,m;

ll fpow(ll x,int k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

ll C(int a,int b)
{
	return fac[a]*inv[b]%MOD*inv[a-b]%MOD;
}

int main()
{
	scanf("%d%d",&n,&m);
	fac[0]=1LL;
	for (int i=1;i<N;i++)
		fac[i]=fac[i-1]*i%MOD;
	inv[N-1]=fpow(fac[N-1],MOD-2);
	for (int i=N-2;i>=0;i--)
		inv[i]=inv[i+1]*(i+1)%MOD;
	for (int i=max(n-m,0);i<=n;i++)
	{
		int sum=((C(n+m,n)-C(n+m,m+i+1)-pre)%MOD+MOD)%MOD;
		ans=(ans+1LL*sum*i)%MOD;
		pre=(pre+sum-MOD);
	}
	printf("%lld",(ans+MOD)%MOD);
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/13507403.html