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

37 篇文章 0 订阅

Description

给定 n n n个正整数 a i a_i ai,令 N + 1 = ∑ a i N+1=\sum a_i N+1=ai
将执行 N N N次操作,每次等概率随机选择一个非零的 a i a_i ai并令其减一,显然 N N N次操作结束之后有且仅有一个 a i = 1 a_i=1 ai=1
对于一开始的 n n n a i a_i ai,分别求出它们最后为 1 1 1的概率
n , a i ≤ 30 n,a_i \leq 30 n,ai30

Analysis

写这题时作死没开longlong,结果还是被乘法忘记转longlong坑死了
以后这种题无脑上longlong,千万别玩火
每次选择非零 a i a_i ai减一,每次操作概率会更改,不好统计答案。
考虑将操作转化成,随机选择 a i a_i ai,若 a i > 0 a_i>0 ai>0则令其减一,否则继续随机,显然答案等价。这样每次操作的每个 a i a_i ai被选中的概率都是 1 / n 1/n 1/n
使用EGF来描述操作序列,为了方便计算,我们把最后一个剩下的数也加入操作序列。不妨假设最后剩下的是 a 1 a_1 a1
对于 2 ≤ i ≤ n 2\leq i\leq n 2in i i i至少出现 a i a_i ai次;对于 1 1 1 1 1 1恰好出现 a 1 a_1 a1次,且一定在序列末出现
G k ( x ) = ∑ i = 0 a k − 1 x i i ! G_k(x)=\sum_{i=0}^{a_k-1}\frac{x^i}{i!} Gk(x)=i=0ak1i!xi,那么合法序列(除最后一项)的EGF就是
F ( x ) = x a 1 − 1 ( a 1 − 1 ) ! ∏ i ≠ 1 ( e x − G i ( x ) ) F(x)=\frac{x^{a_1-1}}{(a_1-1)!}\prod_{i\neq 1}(e^x-G_i(x)) F(x)=(a11)!xa11i̸=1(exGi(x))
答案即为
∑ i ≥ 0 i ! [ x i ] F ( x ) n i + 1 \sum_{i\geq 0}\frac{i![x^i]F(x)}{n^{i+1}} i0ni+1i![xi]F(x)
F ( x ) F(x) F(x)展开,每部分形如 λ x d e j x \lambda x^d e^{jx} λxdejx,其中 λ \lambda λ可以 d p dp dp求出,考虑计算该部分对答案的贡献
λ n d + 1 ∑ i ≥ 0 j i ( d + i ) ! i ! n i \frac{\lambda}{n^{d+1}} \sum_{i\geq 0}\frac{j^i (d+i)!}{i!n^i} nd+1λi0i!niji(d+i)!
= λ d ! n d + 1 ∑ i ≥ 0 ( j n ) i ( d + i i ) =\frac{\lambda d!}{n^{d+1}} \sum_{i\geq 0}(\frac{j}{n})^i {d+i \choose i} =nd+1λd!i0(nj)i(id+i)
= λ d ! n d + 1 ( n n − j ) d + 1 =\frac{\lambda d!}{n^{d+1}} (\frac{n}{n-j})^{d+1} =nd+1λd!(njn)d+1
最后还剩下一个问题,如果对于每个 a i a_i ai我们都暴力做dp来求 λ \lambda λ,令 m = m a x { a i } m=max\{a_i\} m=max{ai}复杂度就是 O ( n 4 m 2 ) O(n^4 m^2) O(n4m2),会TLE
正确姿势是一开始求出 ∏ i ( e x − G i ( x ) ) \prod_{i}(e^x-G_i(x)) i(exGi(x)),对于每个 a i a_i ai再消除它
复杂度 O ( n 3 m 2 ) O(n^3m^2) O(n3m2)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<assert.h>
#define fo(i,a,b) for(int i=(a);i<=(b);++i)
#define fd(i,b,a) for(int i=(b);i>=(a);--i)
using namespace std;
typedef long long ll;
int read(){int n=0,p=1;char ch;for(ch=getchar();ch<'0' || ch>'9';ch=getchar())if(ch=='-') p=-1;for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';return n*p;}
const int N=33,mo=998244353;
void inc(int &x,int y){x=(x+y)%mo;}
int qmi(int x,int n)
{
	int t=1;
	for(x%=mo;n;n>>=1,x=1ll*x*x%mo) if(n&1) t=1ll*t*x%mo;
	return t;
}
int n,m,a[N],f[N][N][N*N],g[N][N*N],fac[N*N],ifac[N*N],inv[N*N];
int main()
{
	n=read();
	fo(i,1,n) a[i]=read(),m=max(m,a[i]);
	fac[0]=ifac[0]=inv[1]=1;
	fo(i,1,n*m) fac[i]=1ll*fac[i-1]*i%mo;
	ifac[n*m]=qmi(fac[n*m],mo-2);
	fd(i,n*m-1,1) ifac[i]=1ll*ifac[i+1]*(i+1)%mo,inv[i+1]=1ll*ifac[i+1]*fac[i]%mo;
	
	f[0][0][0]=1;
	fo(i,1,n)
		fo(j,0,i)
			fo(k,0,i*m)
			{
				if(j) inc(f[i][j][k],f[i-1][j-1][k]);
				fo(l,0,min(a[i]-1,k))
					inc(f[i][j][k],-1ll*f[i-1][j][k-l]*ifac[l]%mo);
			}
	fo(i,1,n)
	{
		memset(g,0,sizeof(g));
		fd(j,n-1,0)
			fo(k,0,(n-1)*m)
			{
				g[j][k]=f[n][j+1][k];
				fo(l,0,min(a[i]-1,k))
					inc(g[j][k],1ll*g[j+1][k-l]*ifac[l]%mo);
			}
		int ans=0;
		fo(j,0,n-1)
			fo(k,0,(n-1)*m) if(g[j][k])
			{
				int lamda=1ll*ifac[a[i]-1]*g[j][k]%mo,d=(a[i]-1)+k;
				int t=1ll*lamda*qmi(inv[n-j],d+1)%mo*fac[d]%mo;
				ans=(ans+t)%mo;
			}
		printf("%d ",(ans%mo+mo)%mo);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值