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

这道题从 \(CSP\) 前就开始咕,该填坑了

发现正着解决问题非常繁琐

我们不如求每个点不为最后被选的概率

假设现在在求 \(i\) 点的答案

我们可以枚举点集 \(S\),使得这些点都在 \(i\) 点选完之后被选完

如果我们枚举点集的长度为 \(len\),那答案的贡献就为 \(\frac{1}{(|s|+1)^{(len+a[i])}}\binom{|s|+a[i]-1}{|s|}\)

【附:为什么其他点对我们选这几个点概率的影响不用考虑】

  • 其实我们是倾定了几个点满足某个性质,在选点的过程中,假设我们选到了集合以外的点,我们可以继续选,直到选的点为集合内的点,那集合内每个点被选的概率就都为以上式子了

直接容斥,考虑到我们只需要知道集合的大小以及序列长度

我们可以背包求出所有情况

询问时对于每一个点做一次退背包求答案

Code
#include <bits/stdc++.h>
#define re register
#define int long long
// #define ll long long
// #define lls long long
#define pir make_pair
#define fr first 
#define sc second
#define db double
using namespace std;
const int mol=998244353;
const int maxn=5e5+10;
const int INF=1e9+7;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return (ans+mol)%mol; }
inline int read() {
    int s=0,w=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
    return s*w;
}

int n,sum,a[1010],fac[1010],inv[1010],invs[33][1010],f[33][1010];
inline void ad(int &a) { a= a>=mol? a-mol:a; }
inline int C(int n,int m) { return fac[n]*inv[m]%mol*inv[n-m]%mol; }
inline void ins(int n,int num) {
	for(re int i=n-1;i>=0;i--) for(re int j=0;j<=sum;j++) if(f[i][j]!=0) {
		for(re int k=0;k<=num;k++) (f[i+1][j+k]-=f[i][j]*C(j+k,k)%mol)%=mol;
	}
}
inline void del(int n,int num) {
	for(re int i=0;i<n;i++) for(re int j=0;j<=sum;j++) if(f[i][j]!=0) {
		for(re int k=0;k<=num;k++) (f[i+1][j+k]+=f[i][j]*C(j+k,k)%mol)%=mol;
	}
}
signed main(void) {
	n=read(); f[0][0]=1; int lim=0;
	for(re int i=1;i<=n;i++) { a[i]=read(); lim+=a[i]; }
	fac[0]=1; for(re int i=1;i<=lim;i++) fac[i]=fac[i-1]*i%mol;
	inv[lim]=qpow(fac[lim],mol-2); for(re int i=lim;i>=1;i--) inv[i-1]=inv[i]*i%mol;
	for(re int i=1;i<=n;i++) {
		invs[i][0]=1;
		for(re int j=1,las=qpow(i,mol-2);j<=lim;j++) invs[i][j]=invs[i][j-1]*las%mol;
    }
    for(re int i=1;i<=n;i++) { ins(i,a[i]-1); sum+=a[i]-1; }
	for(re int t=1;t<=n;t++) {
		int ans=0; 
		sum-=a[t]-1; del(n,a[t]-1); 
		for(re int i=0;i<n;i++) for(re int j=0;j<=sum;j++) {
			(ans+=f[i][j]*invs[i+1][j+a[t]]%mol*C(j+a[t]-1,j)%mol)%=mol;
        }
		sum+=a[t]-1; ins(n,a[t]-1); 
		printf("%lld ",(ans+mol)%mol);
	}
}

posted @ 2021-11-07 16:09  zJx-Lm  阅读(43)  评论(0编辑  收藏  举报