[CF1204E] Natasha, Sasha and the Prefix Sums
[CF1204E] Natasha, Sasha and the Prefix Sums
题意
一个长度为 \(n+m\),有 \(n\) 个 \(1\) 和 \(m\) 个 \(-1\) 的序列 \(a\),定义其最大前缀和为:\(\large \max\{ 0,\max\limits_{1\le i\le n+m}\sum\limits_{j=1}^ia_j \}\)。求算所有可能序列的最大前缀和。
分析
首先我们考虑一种计算总贡献的方法,首先我们有一种朴素的想法,即我们枚举状态 \(s\) 时,求算 \(\sum f(s)\),但是这道题显然我们不能暴力枚举每种情况,我们考虑另外一种情况,若设某个序列的贡献为 \(val\) 时,我们可以使用 \(\sum cnt_{val}\times val\) 来求解。
对于这道题我们可以使用后者来求解,我们考虑前缀和区间以及题目中的定义,显然有 \(val∈[\max(1,n-m),n)\)。而后我们可以考虑使用类似 Catalan 数的方法进行求解,我们考虑把序列中的 \(1\) 看做向右走,序列中的 \(-1\) 看做向左走,则有最大前缀和为过程中坐标的最大值,则我们考虑一种 \(f(k)\) 表示不向右越过 \(k\) 的方案数,则有 \(f(k)\) 表示最大前缀和小于等于 \(k\) 的方案数,显然我们有最大前缀和的方案数为 \(f_k-f_{k-1}\)。而后我们考虑单个 Catalan 序列的求解。
我们不考虑限制条件那么所有的操作方案数为 \(C_{n+m}^m\)。
而后我们考虑这个不越过 \(k\) 的限制条件。显然有所有不合法操作都会抵达 \(k+1\)。那么我们把所有这一时刻后的不合法操作以 \(k+1\) 为对称轴取反。则有最后我们经过一些操作,由原来的终点 \(n-m\) 变为 \(2(k+1)-n+m\)。我们设向右走 \(R\) 步且为正贡献 1,向左走 \(L\) 步且为负贡献 1。则有二元一次方程组 \(L+R=n+m,R-L=2(k+1)-n+m\)。
那么我们解得 \(L=n-k-1,R=m+k+1\)。则有不合法路径数 \(C_{n+m}^{m+k+1}\)。
则有 \(f(k)=C_{n+m}^{m}-C_{n+m}^{m+k+1}\)。
我们考虑总贡献有 \(Ans=\sum_{k=\max(1,n-m)}^{n}k \times (f(k)-f(k-1))\)。
我们考虑使用快速幂+逆元求算组合数。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int mod=998244853;
struct node{
int inv[2000090],fac[2000090];
int qpow(int shu,int cifang){
int ans=1;int k=cifang;
while(k){
if(k&1){ans=ans*shu%mod;ans%=mod;shu=shu*shu%mod;shu%=mod;}
else{shu=shu*shu%mod;shu%=mod;}
k>>=1;
}
return ans%mod;
}
void init(int len){
fac[0]=1;
for(int i=1;i<=len;i++) fac[i]=fac[i-1]*i%mod;
inv[len]=qpow(fac[len],mod-2);
for(int i=len;i;i--){
inv[i-1]=inv[i]*(i)%mod;
}
}
int C(int n,int m){
return fac[n]%mod*inv[m]%mod*inv[n-m]%mod;
}
}lg_get;
int f(int n,int m,int k){
int ans=lg_get.C(n+m,m)%mod-lg_get.C(n+m,m+k+1)%mod;
ans+=mod,ans%=mod;
return ans;
}
void solve(){
scanf("%lld%lld",&n,&m);
// int x=k,y=a;
// int y=k,x=a;
// x--,y--;
// printf("%lld %lld\n",x,y);
int ans=0;
for(int kk=max(1ll,n-m);kk<=n;kk++){
// printf("%d\n",kk);
int tmp=kk%mod*(f(n,m,kk)-f(n,m,kk-1))%mod;
tmp%=mod;
// printf("%lld\n",tmp);
ans+=tmp;
ans+=mod;
ans%=mod;
}
printf("%lld\n",ans);
}
const int MAXN=1e6+7;
signed main(){
lg_get.init(MAXN*2);
// int T;
// cin>>T;
// while(T--) solve();
solve();
}