这个嘛…容斥原理推一推公式就好啦>..<
选定i行,j列,k种颜色
i行可有颜色,也可没有,没有选的不能有涂色
j列类似
k种颜色可出现也可不出现,没有选颜色的不能用
这个有
(k+1)ij
种方案
那么总答案就是
∑i=0N∑j=0M∑k=0CCiNCjMCkC(−1)N+M+C−i−j−k(k+1)ij
我们显然不能接受O(NMC)的复杂度,然而题中400的数据范围奥妙重重,让这个算法水过了>..<我非常不开心
那么我们来想想怎么优化吧
有一个非常显而易见的多项式展开的公式
(X+1)Y=∑i=0YCiY∗Xi
我们倒着来
原式稍稍变一下形
∑i=0N∑k=0C(CiNCkC(−1)N+M+C−i−k ∑j=0MCjM(−1)j((k+1)i)j)
右边那个sigma的右边是不是和多项式展开公式形似呢,嘿嘿嘿
∑i=0N∑k=0C(CiNCkC(−1)N+M+C−i−k(1−(k+1)i)M)
于是时间就变成O(NClogM)啦>..<
O(NMC)水过的,是异端,要批斗
#include <cstdio>
const int MOD = 1000000007;
long long CC[401][401], POW[402][401], OUT, BASE, LOW;
int N, M, C;
inline int inv(int x)
{
return x & 1 ? MOD - 1 : 1;
}
long long POWER(long long a, int b)
{
long long r = 1;
for (; b; b >>= 1)
{
if (b & 1)
r = r * a % MOD;
a = a * a % MOD;
}
return r;
}
int main()
{
scanf("%d%d%d", &N, &M, &C);
for (int i = 0; i <= N || i <= C; i++)
{
CC[i][0] = 1;
for (int j = 1; j <= i; j++)
{
CC[i][j] = CC[i - 1][j - 1] + CC[i - 1][j];
if (CC[i][j] >= MOD)
CC[i][j] -= MOD;
}
}
for (int i = 1; i <= C + 1; i++)
{
POW[i][0] = 1;
for (int j = 1; j <= N; j++)
POW[i][j] = POW[i][j - 1] * i % MOD;
}
for (int i = 0; i <= C; i++)
for (int j = 0; j <= N; j++)
{
BASE = CC[C][i] * CC[N][j] % MOD * inv(N ^ M ^ C ^ i ^ j) % MOD;
LOW = (MOD - POW[i + 1][j]) + 1;
if (LOW >= MOD)
LOW -= MOD;
OUT += BASE * POWER(LOW, M) % MOD;
if (OUT >= MOD)
OUT -= MOD;
}
printf("%lld\n", OUT);
return 0;
}