UNR #3 百鸽笼

题目大意:在UOJ管理员群里一共有\(N\)个管理员,为了容纳这些管理员,vfk准备了\(N+1\)个鸽笼。

为了节省空间,vfk把这些鸽笼堆了起来,共有\(n\)列,第i列放了\(a_i\)个鸽笼,满足 \(\sum a_i=N+1\)。

每当UR结束,管理员们就会按照编号从小到大的顺序回到鸽笼里,每个管理员回来的时候,会先等概率的在所有还有剩余的鸽笼的列中随机一个列,然后住到这列剩下的鸽笼里编号最小的一个中。

现在\(N\)个管理员都回笼了之后,还有一列会空出一个鸽笼。你能对于每一列,求出这一列有空鸽笼的概率吗?

\(a_i \le 30, N\le 30\)

PKUWC2018猎人杀很像。

不必要的一步,问题可以转化为无限选直到只剩一个\(a_i>0\)

对于每个点,枚举一个集合\(S\),算出这个点在这个集合\(S\)所有点之前被删完的概率。显然集合外的操作我们可以忽略。集合内部的操作我们可以忽略不计。

考虑这个点被选完的时候的操作序列,这个东西可以用一个背包做出来。于是有一个\(2^n * somthing\)的复杂度的东西。我们再加一维表示当前的集合大小,就行了。

瞎写一发,发现复杂度达到了\(O(n^4m^2)\),T了。我们把那个背包做完然后撤销就行了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
inline int inv(int x){return qpow(x,mod-2);}
/* math */
const int N = 40, SZ = 910;
int n,a[N];
int binom[2010][2010];
inline void preset(int n=2000){
    binom[0][0]=1;
    for(int i=1;i<=n;i++){
        binom[i][0]=binom[i][i]=1;
        for(int j=1;j<i;j++)binom[i][j]=add(binom[i-1][j-1],binom[i-1][j]);
    }
}
int f[N][SZ];
int g[N][SZ];

int sum = 0;
inline void package(int sz){
    for(int i=1;i<=n;i++){
        for(int j=0;j<=sum;++j){
            g[i][j]=f[i][j];
            for(int d=0;d<sz&&j-d>=0;d++){
                g[i][j]=add(g[i][j],mul(f[i-1][j-d],binom[j][d]));
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<=sum;++j){
            f[i][j]=g[i][j];
        }
    }
}

inline void unpackage(int sz){
    for(int i=1;i<=n;i++){
        for(int j=0;j<=sum;++j){
            g[i][j]=f[i][j];
            for(int d=0;d<sz&&j-d>=0;d++){
                g[i][j]=sub(g[i][j],mul(f[i-1][j-d],binom[j][d]));
            }
            f[i][j]=g[i][j];
        }
    }
}

int main()
{
    preset();
    cin >> n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
    f[0][0]=1;
    for(int i=1;i<=n;i++)package(a[i]);
    for(int i=1;i<=n;i++){
        unpackage(a[i]);
        int ans=0;
        for(int S=1;S<=n;++S){
            for(int len=0;len<=sum;++len){
                int totlen = len+a[i], way = mul(f[S-1][len], binom[len+a[i]-1][a[i]-1]);
                int p=qpow(inv(S),totlen);
                if(S&1) ans=add(ans, mul(p,way));
                else ans=sub(ans, mul(p,way));
            }
        }
        package(a[i]);
        printf("%d ",ans);
    }
    puts("");
}

原文地址:https://www.cnblogs.com/weiyanpeng/p/11116186.html

时间: 2024-08-30 13:50:49

UNR #3 百鸽笼的相关文章

UOJ #390. 【UNR #3】百鸽笼

UOJ #390. [UNR #3]百鸽笼 题目链接 看这道题之前先看一道相似的题目 [PKUWC2018]猎人杀. 考虑类似的容斥: 我们不妨设处理\(1\)的概率. 我们另集合\(T\)中的所有鸽笼都在\(1\)变空之前不为空的,其它的鸽笼随便.要做到这一点,我们只需要令每个\(T\)集合中的鸽笼容量\(--\)就行了.然后我们用背包背出所有序列的方案数(不包括\(1\)),然后在将\(1\)插入序列中.插入时,将\(w_i-1\)个随便插入,然后再将一个放在序列末尾. 具体实现时,我们可以

大陆27个省级行政区片区数据-基于58同城二手房数据

[数据来源]http://www.58.com城市清单http://www.58.com/changecity.html[结果汇总]数目省自治区份数.城市数.行政区县数.58片区数.数据总条数:27.483.3751.9723.12676行政区县数:58片区数=1:2.59.详情请查阅附件. [特别说明] 暂未爬取直辖市数据. 省份 市 省市数 行政区县 行政区县数 58片区名 片区数 29省汇总 505 3751 9723 安徽 合肥 22 蜀山 11 安徽大学 43 安徽 合肥 22 蜀山

2017-2018年毕业面试总结《一》

2017年刚好是大四,准备实习的日子,开始各种找工作,投简历.面试,四处奔波,幸好在大学期间没有白费日子,出来找工作也是非常的上心,尽管多次面试碰但还是一直没有丧气,留下了不少当时的总结,于是写下分享,为了以后N年后查看,想想那时的自己为了找个实习单位,也是拼了,从学校佛山到广州,再到深圳,只要有面试机会都会去尝试,不管成不成功,都去试下,那时特别希望自己能找份像样点的实习单位,也很渴望能够去到大公司,果然如我所愿,最后去了百度广州分公司,从那里开启了我走向社会的第一份程序员工作,非常怀念那一段

三百六十度全景图如何拍摄?

三百六十度全景图如何拍摄?随着全景技术的发展,全景拍摄也成为了一种十分新潮的摄影方式.全景摄影也有很多学问,而且随着全景照片的用途越来越多,拍摄全景的设备也越来越多.今天我们就介绍几种十分另类的360全景图拍摄方法,这些酷雷曼360全景图拍摄方法让你大开眼界. 工具/原料 相机 鱼眼镜头 云台 三角支架 方法/步骤 1 吊锤辅助360全景图拍摄方法 吊线保证拍摄时相机以节点旋转,使用吊线进行全景拍摄线不要太长,50CM以内比较容易控制,有时也到一米多在胸口位置进行拍摄,重锤容易晃动,很难对准.吊

第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装

第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装 当前环境python3.5 ,windows10系统 Linux系统安装 在线安装,会自动安装scrapy模块以及相关依赖模块 pip install Scrapy 手动源码安装,比较麻烦要自己手动安装scrapy模块以及依赖模块 安装以下模块 1.lxml-3.8.0.tar.gz (XML处理库) 2.Twisted-17.5.0.tar.bz2 (用Python编写的异步网络框架) 3.Scrapy-1.4.0.tar.gz

Java千百问_02基本使用(015)_java如何通过汇编方式运行

点击进入_更多_Java千百问-基本使用 1.java如何通过汇编方式运行 java本身不能通过汇编方式运行.但是,我们可以通过某些插件,在运行中将java代码解释为汇编指令,让我们能够通过分析执行的汇编指令来查找一些问题,也可以帮助我们分析和理解JVM是如何解释和编译的(当然java本身的编译和运行和汇编无关). PrintAssembly是JVM的一个运行参数,它允许我们获取在控制台打印java代码翻译成的汇编指令.使用PrintAssembly需要一些插件的支持,这些并不是JVM直接提供的

个、十、百、千、万、亿、兆、京、垓、秭、穰、沟、涧、正、载

个.十.百.千.万.亿.兆.京.垓.秭.穰.沟.涧.正.载 他们的数值 个. 十.数字后1个0 百.数字后2个0 千.数字后3个0 万.数字后4个0 亿.数字后8个0 兆.数字后12个0 京.数字后16个0 垓.数字后20个0 秭.数字后24个0 穰.数字后28个0 沟.数字后32个0 涧.数字后36个0 正.数字后40个0 载.数字后44个0

Android应用之《宋词三百首》(二)

接上回,上回我们讲到MainActivity里面将所有的宋词标题和作者显示到界面的ListView中去,我们接下来的工作是通过点击ListView的Item跳转到ContentActivity里面去显示单个宋词的所有内容,跳转代码例如以下: // 为ListView的Item设置点击监听器 mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterVi

[OpenJudge] 百练2754 八皇后

八皇后 Description 会下国际象棋的人都很清楚:皇后可以在横.竖.斜线上不限步数地吃掉其他棋子.如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题. 对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数.已经知道8皇后问题一共有92组解(即92个不同的皇后串).给出一个数b,要求输出第b个串.串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小. I