1. 程式人生 > >uvalive7040 / cf gym 100548 Color(2014西安區域賽F題)

uvalive7040 / cf gym 100548 Color(2014西安區域賽F題)

Source

題意

n個格子排成一行,有m種顏色,問用恰好k種顏色進行染色,使得相鄰格子顏色不同的方案數。
k106n,m109

分析

在網上看到的幾篇解題報告好像沒講清楚為什麼是容斥(反正我沒看懂。。),所以我也寫一篇。
首先,我們可以從m個顏色中取出k個,即Ckm
接著容易想到 k(k1)n1, 這個是使用不超過k種顏色的所有方案。但我們要求的是恰好使用k種顏色。
假設選出的k種顏色標號為1,2,3,…, k,那麼記 Ai不使用顏色i的方案數,求的就是 |S||A1A2An| 。也就是反過來考慮,我們不考慮用了哪些顏色,我們考慮哪些顏色沒用!減去所有有沒使用顏色的方案的並集,剩下的方案就是使用了所有k種顏色的方案。上式中的 |

S|k(k1)n1 ,後者就可以用容斥原理來求了。注意到我們只是給顏色標了個號,所以後面每一項的應為 Cik(ki)(ki1)n1 的形式,即選出i個不使用的顏色,用剩餘顏色去塗的方案數。完整式子寫起來比較麻煩就不寫了,可以參考其他blog。

程式碼

/*************************************************************************
    > File Name: uvalive_7040.cpp
    > Author: james47
    > Mail: 
    > Created Time: Sat Aug  8 08:47:40 2015
 ************************************************************************/
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int mod = (int)1e9+7; int pow_mod(int a, int exp){ int ret = 1; while(exp){ if (exp&1) ret = (long long)ret * a % mod; a = (long
long)a * a % mod; exp >>= 1; } return ret; } int c[(int)1e6+100]; int inv[(int)1e6+100]; int cal(int n, int m, int k){ if (k == 1 && n == 1) return m; if (k == 1 && n > 1) return 0; int ret = 1, lim = min(k, m - k); for (int i = 1; i <= lim; i++) ret = (long long)ret * (m-i+1) % mod * inv[i] % mod; c[0] = 1; for (int i = 1; i <= k; i++) c[i] = (long long)c[i-1] * (k-i+1) % mod * inv[i] % mod; int tmp, tot = (long long)k * pow_mod(k-1, n-1) % mod; for (int i = 1; i+1 < k; i++){ tmp = (long long)c[i] * (k-i) % mod * pow_mod(k-i-1, n-1) % mod; if (i&1){ tot = tot - tmp; if (tot < 0) tot += mod; } else{ tot = tot + tmp; if (tot >= mod) tot -= mod; } } ret = (long long)ret * tot % mod; return ret; } void init(){ inv[1] = 1; for (int i = 2; i <= 1000000; i++){ inv[i] = (long long)(mod - mod/i) * inv[mod % i] % mod; } } int T, n, m, k; int main() { init(); scanf("%d", &T); int cas = 0; while(T--){ scanf("%d %d %d", &n, &m, &k); printf("Case #%d: %d\n", ++cas, cal(n, m, k)); } return 0; }