【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);
}
}