zoukankan      html  css  js  c++  java
  • CF1096E The Top Scorer

    CF1096E The Top Scorer

    总方案数,直接插板,为 (inom{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{inom{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}inom{n}{i}g(i))

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

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

    发现

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

    可得

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

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

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

    还是插板。设 (p(n,m)=inom{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
    ",ans);
    	return 0;
    }
    
    路漫漫其修远兮,吾将上下而求索
  • 相关阅读:
    java动态代理机制
    Spring的几种注入bean的方式
    java的泛型与反射机制
    java中equals与==的比较
    Java虚拟机JVM简单理解
    java集合类总结
    timersmanager 解析
    rtsp实时流通过rtmp推送到服务端
    udp 视频包网络传输花屏
    GB28181国检推流
  • 原文地址:https://www.cnblogs.com/zzctommy/p/13849524.html
Copyright © 2011-2022 走看看