题意
n n n 个格子排成一行,每个格子的颜色是 m m m 种里面均匀随机的,对于 u ∈ [ i , n ] u\in[i,n] u∈[i,n],求出现次数最多的颜色出现次数为 u u u 的概率,答案模给定质数 p p p。 n ≤ 500 , m ≤ 1 0 8 n\leq 500,m\leq 10^8 n≤500,m≤108,3s。
题解
转化为计算求出现次数最多的颜色出现次数不超过 u u u 的方案数。即: m m m 种颜色,每种可以选 0 到 u u u 个,用来覆盖 m m m 个格子。考虑 EGF,要求的即为: n ! [ x n ] ( ∑ i = 0 u x i i ! ) m n![x^n](\sum\limits_{i=0}^u{x^i \over i!})^m n![xn](i=0∑ui!xi)m。
做 n n n 次多项式快速幂。其中 ln \ln ln 与 exp \exp exp 求值都可以使用 O ( n 2 ) O(n^2) O(n2) 的方式( A = ln B A=\ln B A=lnB 两边求导 A ′ = B ′ B A'={B'\over B} A′=BB′ 之后模拟, exp \exp exp 同理)。
#include<bits/stdc++.h>
using namespace std;
int getint(){
int ans=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
const int N=505;
int n,m,mod;
int fac[N],ifac[N];
int x[N],tmp[N];
int qpow(int x,int y){
int ans=1;
while(y){
if(y&1)ans=ans*1ll*x%mod;
x=x*1ll*x%mod;
y>>=1;
}
return ans;
}
int inv[N];
void get_ln(){
memcpy(tmp,x,sizeof(tmp));
for(int i=0;i<=n;i++)tmp[i]=tmp[i]*1ll*i%mod;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
tmp[i]-=tmp[j]*1ll*j%mod*x[i-j]%mod;
if(tmp[i]<0)tmp[i]+=mod;
}
tmp[i]=tmp[i]*1ll*inv[i]%mod;
}
}
void get_exp(){
memset(tmp,0,sizeof(tmp));
tmp[0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
tmp[i]+=tmp[j]*1ll*x[i-j]%mod*(i-j)%mod;
if(tmp[i]>=mod)tmp[i]-=mod;
}
tmp[i]=tmp[i]*1ll*inv[i]%mod;
}
}
int main(){
n=getint(),m=getint(),mod=getint();
inv[0]=inv[1]=1;for(int i=2;i<=n;i++)inv[i]=(inv[mod%i]*1ll*(mod-mod/i))%mod;
int inv=qpow(qpow(m,n),mod-2);
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*1ll*i%mod;
ifac[n]=qpow(fac[n],mod-2);
for(int i=n-1;i>=0;--i)ifac[i]=ifac[i+1]*(i+1ll)%mod;
assert(ifac[0]==1);
int lst=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=i;j++)x[j]=ifac[j];for(int j=i+1;j<=n;j++)x[j]=0;
get_ln();
for(int j=0;j<=n;j++)x[j]=tmp[j]*1ll*m%mod;
get_exp();
printf("%d ",(tmp[n]-lst+mod)*1ll*fac[n]%mod*inv%mod);
lst=tmp[n];
}
return 0;
}