http://swjtuoj.cn/problem/2382/
题目的难点在于,用k种颜色,去染n个盒子,并且一定要用完这k种颜色,并且相邻的格子不能有相同的颜色,
打了个表发现,这个数是s(n, k) * k!
s(n, k)表示求第二类斯特林数。
那么关键是怎么快速求第二类斯特林数。
这里提供一种O(k)的算法。
第二类斯特林数:
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> LL quick_pow(LL a, LL b, LL MOD) { //求解 ab % MOD的值 LL base = a % MOD; LL ans = 1; //相乘,所以这里是1 while (b > 0) { if (b & 1) { //用quick_mul防止Miller_Rabin那里溢出。 ans = ans * base % MOD; //如果这里是很大的数据,就要用quick_mul } base = base * base % MOD; //notice。每次的base是自己base倍 b >>= 1; } return ans; } LL fac[1000000 + 20]; LL C2(LL n, LL m, LL MOD) { if (n < m) return 0; //防止sb地在循环,在lucas的时候 if (n == m) return 1 % MOD; LL ans1 = 1; LL ans2 = 1; LL mx = max(n - m, m); //这个也是必要的。能约就约最大的那个 LL mi = n - mx; for (int i = 1; i <= mi; ++i) { ans1 = ans1 * (mx + i) %MOD; ans2 = ans2 * i % MOD; } return (ans1 * quick_pow(ans2, MOD - 2, MOD) % MOD); //这里放到最后进行,不然会很慢 } LL C(LL n, LL m, LL MOD) { if (n > 1000000) return C2(n, m, MOD); return fac[n] * quick_pow(fac[n - m], MOD - 2, MOD) % MOD * quick_pow(fac[m], MOD - 2, MOD) % MOD; } const int MOD = 1e9 + 7; void add(LL &x, LL y) { x += y; x += MOD; if (x >= MOD) x %= MOD; } void work() { int n, m, k; scanf("%d%d%d", &n, &m, &k); if (n == 1) { printf("%d\n", m); return; } if (k == 1) { printf("0\n"); return; } LL ans = 0; LL res = C(m, k, MOD); k--; n--; for (int i = 0; i <= k; ++i) { if (i & 1) { add(ans, -(C(k, i, MOD) * quick_pow(k - i, n, MOD)) % MOD); } else { add(ans, (C(k, i, MOD) * quick_pow(k - i, n, MOD) % MOD)); } } ans = ans * quick_pow(fac[k], MOD - 2, MOD) % MOD; ans = ans * fac[k + 1] % MOD; ans = ans * res % MOD; printf("%lld\n", ans); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif fac[0] = 1; for (int i = 1; i <= 1000000; ++i) { fac[i] = fac[i - 1] * i % MOD; } int t; scanf("%d", &t); while (t--) work(); return 0; }
时间: 2024-10-05 06:17:30