Loading

CF1096E The Top Scorer

CF1096E The Top Scorer

总方案数,直接插板,为 \(\binom{s-r+p-1}{p-1}\) ,意思是先分 \(r\) 分给小明,然后再分为 \(p-1\) 个非负整数和

接下去算合法的方案数

枚举小明的最高分为 \(i\) ,令 \(j\) 个人与小明同分,设 \(f(x,y,z)\) 表示 \(x\) 个数,和为 \(y\) ,最大值不超过 \(z\) 的方案数,那么合法的方案数等于

\[\sum_{i=r}^{s}\sum_{j=0}^{p}\dfrac{\binom{p-1}{j}f(p-j-1,s-(j+1)*i,i-1)}{j+1} \]

考虑如何求 \(f\)

我看了题解才知道,这东西触及到我的知识盲区了,怎么一不小心做到这种题

考虑设所求答案为 \(g(n)\)\(g(i)\) 表示恰有 \(n-i\) 个不合法状态的情况数。

再搞一个函数 \(h(i)\) 表示至少 \(n-i\) 个不合法状态的方案数

非常显然 \(h(i)=\sum_{j=1}^{i}\binom{n}{i}g(i)\)

二项式反演的公式拿出来:

\[f(n)=\sum_{i=1}^{n}\binom{n}{i}g(i)\Leftrightarrow g(n)=\sum_{i=1}^{n}(-1)^{n-i}\binom{n}{i}f(i) \]

发现

\[g(x)=\sum_{i=1}^{x}(-1)^{n-i}\binom{n}{i}h(i) \]

可得

\[g(n)=\sum_{i=1}^{n}(-1)^{n-i}\binom{n}{i}h(i) \]

发现这个 \(h(i)\) 非常好算

直接先让 \(n-i\) 个状态不合法掉,其余随机分配就好了。

还是插板。设 \(p(n,m)=\binom{n+m-1}{m-1}\) 表示 \(m\) 个非负整数加起来等于 \(n\) 的方案数

\[h(i)=p(x-(i+1)*(z+1),x) \]

带回去就好了

有两个细节:

  • 组合数预处理不能只处理到 \(5000\) ,最后答案还要乘的那个分母要用到 \(5100\)

  • \(f(0,0,z)=1\) ,注意特判

#include<bits/stdc++.h>
typedef long long LL;
typedef double db;
#define x first
#define y second
#define sz(v) (int)v.size()
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
	while(isdigit(c))x=x*10+c-'0',c=getchar();
	return f?x:-x;
}
const int mod=998244353;
const int N=10005;
int p,s,r,ans;
int jc[N],jv[N],inv[N];
int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
void init(const int&N){
	jc[0]=1;
	for(int i=1;i<=N;++i)jc[i]=1ll*jc[i-1]*i%mod;
	jv[N]=qpow(jc[N],mod-2);
	for(int i=N-1;i>=0;--i)jv[i]=1ll*jv[i+1]*(i+1)%mod;
	inv[1]=1;
	for(int i=2;i<=N;++i)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
int C(int n,int m){return 1ll*jc[n]*jv[m]%mod*jv[n-m]%mod;}
int g(int n,int m){return C(n+m-1,m-1);}//sum of m non-neg integers=n
int f(int x,int y,int z){//number=x,sum=y,limit=z
	if(!x&&!y)return 1;
	int res=0,flg=(x&1)?-1:1;
	for(int i=0;i<=x;++i,flg*=-1)
		if(y-(z+1)*(x-i)>=0)res=(res+1ll*flg*C(x,i)*g(y-(z+1)*(x-i),x)%mod)%mod;
	return res;
}
signed main(){
	init(6000);
	p=read(),s=read(),r=read();
	for(int i=r;i<=s;++i){
		for(int j=0;(j+1)*i<=s&&j<p;++j){
			ans=(ans+1ll*C(p-1,j)*f(p-j-1,s-(j+1)*i,i-1)%mod*inv[j+1]%mod)%mod;
		}
	}
	ans=1ll*ans*qpow(C(s-r+p-1,p-1),mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
posted @ 2020-10-20 22:27  zzctommy  阅读(76)  评论(0编辑  收藏  举报