传送门
N
O
I
NOI
NOI 模拟比
C
S
P
CSP
CSP 模拟简单干脆就都说成
C
S
P
CSP
CSP 模拟
显然按层转移,并且颜色种类没有关系,只关心个数
f
i
,
j
f_{i,j}
fi,j 表示到第
i
i
i 层,有
j
j
j 种颜色的方案数
枚举填几种颜色,
v
a
l
(
i
,
j
)
val(i,j)
val(i,j) 表示
i
i
i 个空格
j
j
j 个颜色的方案数即
j
∗
(
j
−
1
)
i
−
1
j*(j-1)^{i-1}
j∗(j−1)i−1
f
i
,
j
=
∑
k
!
=
j
f
i
−
1
,
k
∗
(
m
k
)
∗
v
a
l
(
a
i
,
j
)
+
f
i
−
1
,
j
∗
(
(
m
j
)
−
1
)
∗
v
a
l
(
a
i
,
j
)
f_{i,j}=\sum_{k!=j}f_{i-1,k}*\binom{m}{k}*val(a_i,j)+f_{i-1,j}*(\binom{m}{j}-1)*val(a_i,j)
fi,j=k!=j∑fi−1,k∗(km)∗val(ai,j)+fi−1,j∗((jm)−1)∗val(ai,j)
发现把多加的减掉即可
f
i
,
j
=
s
u
m
i
−
1
∗
(
m
j
)
∗
v
a
l
(
a
i
,
j
)
−
f
i
−
1
,
j
∗
v
a
l
(
a
i
,
j
)
f_{i,j}=sum_{i-1}*\binom{m}{j}*val(a_i,j)-f_{i-1,j}*val(a_i,j)
fi,j=sumi−1∗(jm)∗val(ai,j)−fi−1,j∗val(ai,j)
然后发现模数任意,组合数已经凉了,
e
x
l
u
c
a
s
exlucas
exlucas ???
有一个非常巧妙的做法是,我们考虑把组合数改成
m
!
(
m
−
j
)
!
\frac{m!}{(m-j)!}
(m−j)!m!,这样就可以简单预处理
然后发现多出来的
j
!
j!
j! 恰好是
v
a
l
(
i
,
j
)
val(i,j)
val(i,j) 中 不考虑颜色顺序的方案数
由于
v
a
l
(
i
,
j
)
val(i,j)
val(i,j) 不考虑颜色顺序,如果填新的颜色钦定是最大的颜色
那么有
v
a
l
(
i
,
j
)
=
v
a
l
(
i
−
1
,
j
−
1
)
+
v
a
l
(
i
−
1
,
j
)
∗
(
j
−
1
)
val(i,j)=val(i-1,j-1)+val(i-1,j)*(j-1)
val(i,j)=val(i−1,j−1)+val(i−1,j)∗(j−1)
感觉好巧妙,通过修改定义解决了组合数的问题
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
int Mod;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1, a=mul(a,a)) if(b&1) ans=mul(ans, a); return ans;}
cs int N = 1e6 + 5, M = 5e3 + 5;
int n, m, C[M], S[M][M];
vector<int> f[N];
int sum[N], a[N];
int g[N], fac[N];
int main(){
n = read(), m = read(), Mod = read();
g[0] = 1;
for(int i = 1; i <= m; i++){
g[i] = mul(g[i - 1], m - i + 1);
}
S[0][0] = 1;
for(int i = 1; i <= M - 5; i++)
for(int j = 1; j <= i; j++)
S[i][j] = add(S[i - 1][j - 1], mul(j - 1, S[i - 1][j]));
fac[0] = 1;
for(int i = 1; i <= M - 5; i++) fac[i] = mul(fac[i-1], i);
sum[0] = 1;
for(int i = 1; i <= n; i++){
a[i] = read();
f[i].resize(a[i] + 1);
for(int j = 1; j <= min(m, a[i]); j++){
f[i][j] = mul(sum[i - 1], mul(g[j], S[a[i]][j]));
if(j <= a[i - 1])
f[i][j] = add(f[i][j], Mod - mul(fac[j], mul(S[a[i]][j], f[i - 1][j])));
sum[i] = add(sum[i], f[i][j]);
}
} cout << sum[n]; return 0;
}