题目描述:
解题思路:
观察题目的性质:
1.中间列不存在第一列和第
m
m
m列同时不存在的颜色。
证明:假设第
j
j
j列具有第一列和第
m
m
m列都没有的颜色。根据题目的性质,我们知道第
[
1
,
j
−
1
]
[1,j-1]
[1,j−1]列的颜色种类和
[
j
,
m
]
[j,m]
[j,m]列的颜色种数相同。我们知道
[
1
,
j
]
[1,j]
[1,j]的颜色种类一定比
[
1
,
j
−
1
]
[1,j-1]
[1,j−1]的多,而
[
j
+
1
,
m
]
[j+1,m]
[j+1,m]的颜色种类一定不比
[
j
,
m
]
[j,m]
[j,m]的多,由此可知不相等。
2.中间列不存在第一列或者第
m
m
m列不存在的颜色。
证明同上。
因此我们知道中间列的颜色一定是第一列和第
m
m
m列颜色的交集。枚举第一列和第
m
m
m列颜色的交集即可。
这里要额外维护一个
d
p
dp
dp数组,
d
p
[
i
]
dp[i]
dp[i]表示用i个颜色去染
n
n
n个方格的方案数,容斥原理维护即可。
复杂度
O
(
n
2
)
O(n^2)
O(n2)。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6 + 100;
const int MOD = 1e9 + 7;
int qpow(int x, int n) {
int res = 1;
while (n > 0) {
if (n & 1) res = 1LL * res * x % MOD;
x = 1LL * x * x % MOD;
n /= 2;
}
return res;
}
int n, m, k;
int fac[N], rev[N], rff[N], dp[N];
int C(int n, int m) {
if (m < 0 || m > n) return 0;
return 1LL * fac[n] * rff[m] % MOD * rff[n - m] % MOD;
}
void init() {
fac[0] = fac[1] = rev[0] = rev[1] = rff[0] = rff[1] = 1;
for (int i = 2; i < N; i++) {
fac[i] = 1LL * fac[i - 1] * i % MOD;
rev[i] = MOD - 1LL * MOD / i * rev[MOD % i] % MOD;
rff[i] = 1LL * rff[i - 1] * rev[i] % MOD;
}
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = qpow(i, n);
for (int j = i - 1; j >= 1; j--) {
dp[i] = (dp[i] - 1LL * C(i, j) * dp[j] % MOD + MOD) % MOD;
}
}
}
int main() {
//freopen("0.txt", "r", stdin);
scanf("%d%d%d", &n, &m, &k);
init();
int ans = 0;
for (int i = 1; i <= n; i++) {
int co = qpow(i, n * (m - 2));
for (int t = 0; i + t <= n && i + 2 * t <= k; t++) {
ans = (ans + 1LL * C(k, i) * C(k - i, t) % MOD * C(k - i - t, t) % MOD
* dp[i + t] % MOD * dp[i + t] % MOD
* co) % MOD;
}
}
if (m == 2) for (int i = 1; 2 * i <= k; i++) ans = (ans + 1LL * C(k, i) * C(k - i, i) % MOD * dp[i] % MOD * dp[i]) % MOD;
printf("%d\n", ans);
return 0;
}