• CF1096E The Top Scorer


    题目传送门:CF1096E

    洛谷入口

    题目大意:

    (p个人,每个人有得分a_i)
    (总得分∑a_i=s)
    (第一个人得分a_1≥r)
    (得分最高的人可以获胜,如果多个人得分最高,则等概率随机其中一个人获胜)
    (问第一个人获胜的概率(运算皆对998244353取模))

    数据范围

    (circ) (1le ple100)
    (circ) (0le rle sle5000)

    题解

    这题算概率,就是获胜方案数除以总情况数
    那要求获胜方案数就可以试着去(DP)
    首先就先枚举获胜者的分数,假设为(i)
    接下来再假设有(j)个人都是这个分数(i)(包含此获胜者)
    那么剩余人还有(p-j)
    剩余分数还有(s-i imes j)
    而且这些人分数都不到(i)
    剩余的人分一些分简单,但如何让每个人得分都不超过(i)呢?
    其实可以用容斥的思想做一下
    我们先考虑至少(0)人超过要求的方案数
    再减去至少(1)人的方案数
    会发现减多了,于是再加回至少(2)人的方案数
    …………………………
    最后就加上((-1)^i imes)至少p-j人方案数
    那对于至少(x)人,要求其超过(lim-1)的求法:
    先给这(x)人每人分个(lim)的分数
    然后再按照隔板法来分(要选其中元素可为(0)的方法)
    这样就可以算出一个通式:
    ((-1)^x imes C_p^x imes C^{p-1}_{s-lim imes x+p-1})
    (i)再按照(0)((p-j))枚举即可解决对于问题(Q(总个数s,总人数p,限制lim))的方案数
    那把这个套进去大的轮廓会得到答案求法:
    (sumlimits^{s}_{i=r}sumlimits^{p}_{j=1}Q(s-i imes j,p-j,i) imes C^{j-1}_{p-1}/j)
    其实理解到这,总情况求法肯定都没问题了吧
    就是(C^{p-1}_{s-r+p-1})
    那么解题步骤就这些
    式子没啥进一步推的,这个复杂度就可以过了

    注意事项

    建议把所有范围内的组合数都求一遍
    ①.组合数递推式是一个公式(其实可以用实际问题的方式轻松证明)
    (C^{j}_{i}=C^{j}_{i-1}+C^{j-1}_{i-1})
    注意初始化(C^0_i都为1)

    ②.逆元的线性求法有一个公式
    (inv_i=mod-(mod/i) imes inv_{mod\%i}\%mod)
    初始化的话记得加个(inv_1=1)

    ③.最后除以总情况时最好用个费马小定理解决
    (说到费马小定理就别忘了带上快速幂)

    好了就这些了好像挺多的,下面上代码!↓↓↓

    AC代码

    #include<bits/stdc++.h>
    #define maxn 5200
    #define int  long long//懒的表现
    using namespace std;
    int mod=998244353,inv[maxn],c[maxn+10][maxn+10],p,s,r,ans;//懒*2
    void init(){//初始化inv&&c
    	inv[1]=1;
    	for(int i=2;i<=p;i++)inv[i]=mod-(mod/i)*inv[mod%i]%mod;
    	c[0][0]=1;
    	for(int i=1;i<=maxn;i++){
    		c[0][i]=1;
    		for(int j=1;j<=i;j++)c[j][i]=(c[j][i-1]+c[j-1][i-1])%mod;
    	}
    }
    int ksm(int x,int y){
    	int tot=1,tmp=x;
    	while(y){
    		if(y&1)tot=tot*tmp%mod;
    		tmp=tmp*tmp%mod;
    		y>>=1;
    	}
    	return tot;
    }
    int C(int a,int b){//为了谨慎而存在
    	if(a>b||a<0||b<0)return 0;
    	return c[a][b];
    }
    int jj(int sum,int x,int lim){
    	if(sum==0)return 1;
    	if(sum<0)return 0;
    	int tot=0;
    	for(int i=0;i<=x;i++)tot=(tot+((i&1)?998244352:1)*c[i][x]%mod*C(x-1,sum-i*lim+x-1))%mod;
    	return tot;
    }
    signed main(){
    	cin>>p>>s>>r;
    	init();
    	for(int i=r;i<=s;i++){
    		for(int j=1;j<=p;j++){
    			if((p-j)*(i-1)+i*j<s)continue;
    			ans=(ans+jj(s-i*j,p-j,i)*C(j-1,p-1)%mod*inv[j])%mod;
    		}
    	}
    	cout<<ans*ksm(c[p-1][s-r+p-1],mod-2)%mod;
    }
    

    编辑不易,支持一下吧,关注,点赞,评论都好!

    THE END

    Reality&Imagine
  • 相关阅读:
    Java StringBuilder、基本类型的包装类
    立个Flag不学好PHP誓不罢休
    LAMP搭建 转
    CentOS使用yum源中自带的rpm包安装LAMP环境
    CentOS RedHat YUM 源扩展补充(32位、64位均有)
    解决phpmyadmin上传文件大小限制的配置方法
    lanmp v2.5一键安装包发布(包括lamp,lnmp,lnamp安装)
    图像处理 jpg png gif svg
    NAT模式/路由模式/全路由模式 (转)
    网页制作中绝对路径和相对路径的区别
  • 原文地址:https://www.cnblogs.com/yang-RA-NOI/p/12594003.html
Copyright © 2020-2023  润新知