百鸽笼

题解

首先,我们依然可以像上道题一样进行类似的转化。
每次操作时会随机一个使它减小111,我们的目的是当所有数都减到⩽0\leqslant 0⩽0,统计每个数时最后一个见得概率。
我们不妨去尝试枚举aia_iai​作为一个最后减到000的数,那么相当于要求在之前的减小序列中,这个数会出现ai−1a_i-1ai​−1次,其它数会出现大于等于aja_jaj​次。
可以尝试通过EGFEGFEGF进行表示,其中我们定义Fi(x)F_i(x)Fi​(x)表示固定点iii作为末尾端点时的生成函数,显然有:
Fi(x)=xai−1(ai−1)!∏j≠i(∑k=aj∞xkk!)=xai−1(ai−1)!∏j≠i(ex−∑k=0aj−1xkk!)F_i(x)=\frac{x^{a_i-1}}{(a_i-1)!}\prod_{j\ne i}(\sum_{k=a_{j}}^{\infty}\frac{x^k}{k!})=\frac{x^{a_i-1}}{(a_i-1)!}\prod_{j\ne i}(e_x-\sum_{k=0}^{a_j-1}\frac{x^k}{k!}) Fi​(x)=(ai​−1)!xai​−1​j​=i∏​(k=aj​∑∞​k!xk​)=(ai​−1)!xai​−1​j​=i∏​(ex​−k=0∑aj​−1​k!xk​)我们记AnsiAns_iAnsi​表示aia_iai​的答案,显然这个答案是可以通过Fi(x)F_i(x)Fi​(x)算出来的。
Ansi=∑j=0∞j![xj]Fi(x)nj+1Ans_i=\sum_{j=0}^{\infty}\frac{j![x^j]F_i(x)}{n^{j+1}} Ansi​=j=0∑∞​nj+1j![xj]Fi​(x)​由于Fi(x)F_i(x)Fi​(x)中的exe^xex展开后次数是会达到无限大的,可能不太好算,我们不妨先记y=exy=e^xy=ex,将它先看成一个二元生成函数,这样就可以比较容易的算出每个[xjyk][x^jy^k][xjyk]的系数,再与xjykx^jy^kxjyk中每个xxx次项的系数乘起来。
显然,有
Ansi=∑j=0∞f(j,k)[xjyk]Fi(x)f(i,j)=1ni+1∑k=0∞jk(i+k)!nkk!=1ni+1∑k=0∞(jn)k(i+k)i‾Ans_i=\sum_{j=0}^{\infty}f(j,k)[x^jy^k]F_i(x)\\ f(i,j)=\frac{1}{n^{i+1}}\sum _{k=0}^{\infty}\frac{j^k(i+k)!}{n^{k}k!}=\frac{1}{n^{i+1}}\sum_{k=0}^{\infty}(\frac{j}{n})^k(i+k)^{\underline{i}} Ansi​=j=0∑∞​f(j,k)[xjyk]Fi​(x)f(i,j)=ni+11​k=0∑∞​nkk!jk(i+k)!​=ni+11​k=0∑∞​(nj​)k(i+k)i​如果我们将jn\frac{j}{n}nj​看作一个变元,那么我们后面这个式子相当于一个对一个多项式求iii次导。
可以得到
f(i,j)=1ni+1(∑k=0∞(jn)k)(i)=1ni+1(11−(jn))(i)=1ni+1(11−jn)i+1=i!(n−d)i+1f(i,j)=\frac{1}{n^{i+1}}(\sum_{k=0}^{\infty}(\frac{j}{n})^k)^{(i)}=\frac{1}{n^{i+1}}(\frac{1}{1-(\frac{j}{n})})^{(i)}=\frac{1}{n^{i+1}}(\frac{1}{1-\frac{j}{n}})^{i+1}=\frac{i!}{(n-d)^{i+1}} f(i,j)=ni+11​(k=0∑∞​(nj​)k)(i)=ni+11​(1−(nj​)1​)(i)=ni+11​(1−nj​1​)i+1=(n−d)i+1i!​这样,我们就可以快速计算f(i,j)f(i,j)f(i,j)了。

好了,接下来剩下的就只有前面的Fi(x)F_i(x)Fi​(x)该怎么求了。
单个Fi(x)F_i(x)Fi​(x)显然是可以通过背包计算的,但如果每个都这样算的话复杂度会达到O(n4m2)O\left(n^4m^2\right)O(n4m2),其中mmm为aia_iai​的大小。
但实际上考虑到我们整个多项式乘法的转移是呈现一个有向图的形式,大概是这样的

其中最后一列最开始是没有值的,所以我们可以考虑先将所有的多项式乘在一起,再一个一个回退求解。
这样就可以做到O(n3m2)O\left(n^3m^2\right)O(n3m2)了。

源码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
#define MAXN 905
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lowbit(x) (x&-x)
const int mo=998244353;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=200000;
const int INF=0x3f3f3f3f;
const double LOG310=log(10)/log(3);
const double Pi=acos(-1.0);
const double eps=1e-9;
const int orG=3,ivG=332748118;
const int lm=10;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,a[35],all,fac[MAXN],inv[MAXN],ff[MAXN];
int summ,dp[35][MAXN],g[35][MAXN];
void init(){fac[0]=fac[1]=inv[0]=inv[1]=ff[1]=1;for(int i=2;i<=max(n,all);i++){fac[i]=1ll*i*fac[i-1]%mo;ff[i]=1ll*(mo-mo/i)*ff[mo%i]%mo;inv[i]=1ll*ff[i]*inv[i-1]%mo;}
}
int main(){read(n);for(int i=1;i<=n;i++)read(a[i]),all+=a[i]-1;init();dp[0][0]=1;for(int i=1,sum=0;i<=n;i++){for(int j=0;j<i;j++)for(int k=0;k<=sum;k++){Add(g[j+1][k],dp[j][k],mo);for(int l=0;l<a[i];l++)Add(g[j][k+l],mo-1ll*inv[l]*dp[j][k]%mo,mo);}sum+=a[i]-1;for(int j=0;j<=i;j++)for(int k=0;k<=sum;k++)dp[j][k]=g[j][k],g[j][k]=0;}for(int i=1;i<=n;i++){int up=all-a[i]+1,ans=0;for(int j=n-1;j>=0;j--)for(int k=0;k<=up;k++){g[j][k]=dp[j+1][k];for(int l=0;l<a[i]&&l<=k;l++)Add(g[j][k],1ll*inv[l]*g[j+1][k-l]%mo,mo);}for(int j=0;j<n;j++)for(int k=a[i]-1;k<=all;k++){int tmp=1ll*g[j][k-a[i]+1]*fac[k]%mo*inv[a[i]-1]%mo;Add(ans,1ll*tmp*qkpow(ff[n-j],k+1,mo)%mo,mo),g[j][k-a[i]+1]=0;}printf("%d ",ans);}puts("");return 0;
}

谢谢!!!

[UNR #3]百鸽笼相关推荐

  1. UNR #3 百鸽笼

    题目大意:在UOJ管理员群里一共有\(N\)个管理员,为了容纳这些管理员,vfk准备了\(N+1\)个鸽笼. 为了节省空间,vfk把这些鸽笼堆了起来,共有\(n\)列,第i列放了\(a_i\)个鸽笼, ...

  2. [uoj390][UNR #3]百鸽笼【dp】【容斥原理】

    [题目链接] http://uoj.ac/problem/390 [题解] 考虑容斥原理,计算第 i i i列的时候,可以强制一些列在它之后被选取完,其他的列就不用处理了. 那么直到i" r ...

  3. UOJ #390 【UNR #3】百鸽笼 容斥+DP

    题目分析 算法0 每个管理员选哪一列,将构成一个长度为 N − 1 N-1 N−1的序列,序列的种数可以通过经典的将 a a a个相同元素插入到一个没有该元素的长度为 b b b的序列里问题,轻松求出 ...

  4. 【UOJ #390】【UNR #3】百鸽笼(指数型生成函数,二项式定理)

    题面

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

    Description 给定 n n n个正整数 a i a_i ai​,令 N + 1 = ∑ a i N+1=\sum a_i N+1=∑ai​ 将执行 N N N次操作,每次等概率随机选择一个非 ...

  6. JZOJ 5933. 【NOIP2018模拟10.27】百鸽笼

    Description Input 从文件 pigeon.in 中读入数据. 输入第一行包含两个正整数 n, m ,分别表示初始鸽笼数与操作个数. 第二行包含 n 个正整数,第 i 个数表示从左往右第 ...

  7. 【JZOJ A组】百鸽笼

    Description Input 从文件 pigeon.in 中读入数据. 输入第一行包含两个正整数 n, m ,分别表示初始鸽笼数与操作个数. 第二行包含 n 个正整数,第 i 个数表示从左往右第 ...

  8. NOIP前的刷题记录

    因为这几天要加油,懒得每篇都来写题解了,就这里记录一下加上一句话题解好了 P4071 [SDOI2016]排列计数   组合数+错排 loj 6217 扑克牌 暴力背包 P2511 [HAOI2008 ...

  9. 组合数学学习笔记(未完待续

    这学期学了不少组合数学,期末给他补完. 算法竞赛考得很多的部分啊 这个还是很重要的 在目前的算法竞赛中有三大计数考点 1)组合计数 2)线性计数 3)群论计数 其中群论计数比较困难,我又不知道什么是线 ...

最新文章

  1. FastJson解析对象及对象数组--项目经验
  2. python pandas.DataFrame选取、修改数据
  3. boost::mp11::mp_transform_third相关用法的测试程序
  4. Android深入浅出系列之Android工具的使用—调试桥ADB(二)
  5. GPU Gems1 - 21 实时辉光(Real-Time Glow)
  6. 静态链接库LIB和动态链接库DLL的区别 创建和示例
  7. 匿名内部类和匿名类_匿名schanonymous
  8. linux下memcache安装
  9. 对偶上升实例-MATLAB代码
  10. 对于springmvc的入门学习 2021-04-19
  11. 【图像处理】美图秀秀使用技巧:抠图、透明、改色、教程
  12. NanoHTTPD服务
  13. 【悟空云课堂】第四十三期:空指针解引用CWE-476: NULL Pointer Dereference
  14. 【异常处理】The CXX compiler identification is unknown
  15. 数据库的列类型与字段属性
  16. AD19导出Gerber文件-嘉立创打板
  17. 顶会论文笔记:联邦学习——ATPFL: Automatic Trajectory Prediction Model Design under Federated Learning Framework
  18. 用链表实现对二进制数加1的运算
  19. 高级编程语言的发展历程(机器语言、汇编语言、高级语言)
  20. rand随机函数和srand初始化种子函数

热门文章

  1. 【敏捷5.2】用户故事的层次和用户故事地图
  2. 推挽输出、开漏输出和悬空输入等
  3. Oracle数据库:约束条件:主键约束、唯一约束、检查约束、非空约束、外键约束、默认值填写
  4. memset函数原型
  5. 解决阿里云此手机号码绑定的账户数已达上限的方法
  6. IP地址划分【分类:A类 B类 C类 D类 E类】
  7. (非常重要).Net Core应用框架Util介绍(学习Util)
  8. Mysql时间函数的坑
  9. js中耦合与解耦问题总结
  10. 基于时间序列AR模型的PHM预测