ARC062 - F. Painting Graphs with AtCoDeer (Polya+點雙聯通分量)

來源:互聯網
上載者:User

標籤:char   就是   \n   類型   graphs   har   pac   getc   display   

似乎好久都沒寫部落格了....趕快來補一篇

  • 題意: 給你一個 \(n\) 個點 , 沒有重邊和自環的圖 .
    有 \(m\) 條邊 , 每條邊可以染 \(1 \to k\) 中的一種顏色 .
    對於任意一個簡單環 , 可以將它的邊的顏色進行旋轉任意位 .
    詢問本質不同的染色方案數個數 .

  • 資料範圍:
    \(1\le n \le 50\\ 1 \le m \le 100\\1 \le k \le 100\\\)

  • 題解:

將邊分為 3種類型:

  1. 不屬於任何一個簡單環 , 它的貢獻為 \(k\) .
  2. 屬於且僅屬於一個簡單環 , 設環長為 \(n\) . 它的貢獻就是
    \[\displaystyle \frac{1}{n} \sum_{i=0}^{n-1} k^{\gcd(i, n)}\]
    這個就是類似於項鏈染色的方案數求解 , 原因見 此篇部落格 .

  3. 屬於多個環 . 能夠證明可以通過旋轉來交換任意兩條邊的顏色 .
    於是本質不同若且唯若有一種顏色數量不同 ,
    其貢獻就是利用隔板法 把 \(m\) 條邊 分成 \(k\) 組的方案數 (每組不一定要有邊)
    那麼我們就加入多的 \(k - 1\) 個隔板 , 然後貢獻就是
    \[{n + k - 1 \choose k - 1}\]

這個全都可以利用 \(Tarjan\) 求點雙聯通分量 (求割點的方法) 來判斷種類 , 並在其中計算 .
時間複雜度就是 \(O(n+m)\) 輕鬆通過此題.

  • 代碼:
#include <bits/stdc++.h>#define For(i, l, r) for(int i = (l), i##end = (int)(r); i <= i##end; ++i)#define Fordown(i, r, l) for(int i = (r), i##end = (int)(l); i >= i##end; --i)#define Set(a, v) memset(a, v, sizeof(a))using namespace std;bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}inline int read() {    int x = 0, fh = 1; char ch = getchar();    for (; !isdigit(ch); ch = getchar() ) if (ch == ‘-‘) fh = -1;    for (; isdigit(ch); ch = getchar() ) x = (x << 1) + (x << 3) + (ch ^ ‘0‘);    return x * fh;}void File() {#ifdef zjp_shadow    freopen ("F.in", "r", stdin);    freopen ("F.out", "w", stdout);#endif}const int N = 55, M = 205;typedef long long ll;const ll Mod = 1e9 + 7;ll fpm(ll x, int power) {    ll res = 1;    for (; power; power >>= 1, (x *= x) %= Mod)        if (power & 1) (res *= x) %= Mod;    return res;}ll fac[M], ifac[M];void Init(int maxn) {    fac[0] = ifac[0] = 1ll;    For (i, 1, maxn) fac[i] = fac[i - 1] * i % Mod;    ifac[maxn] = fpm(fac[maxn], Mod - 2);    Fordown (i, maxn - 1, 1) ifac[i] = ifac[i + 1] * (i + 1) % Mod;}ll C(int m, int n) {    if (m > n || n < 0 || m < 0) return 0ll;    return fac[n] * ifac[m] % Mod * ifac[n - m] % Mod;}set <int> Point;int n, m, k; ll ans = 1ll;ll Polya(int n) {    ll res = 0;    For (i, 1, n) (res += fpm(k, __gcd(n, i))) %= Mod;    return res * fpm(n, Mod - 2) % Mod;}ll Permu(int m) { return C(k - 1, m + k - 1); }vector<int> G[N];int dfn[N], lowlink[N], sta[N], top;void Tarjan(int u, int fa) {    static int clk = 0;    dfn[u] = lowlink[u] = (++ clk); sta[++ top] = u;    for (int v : G[u]) if (!dfn[v]) {        Tarjan(v, u), chkmin(lowlink[u], lowlink[v]);        if (lowlink[v] >= dfn[u]) {            Point.clear();            int n = 0, m = 0, Last;            do Point.insert(Last = sta[top --]), ++ n; while (Last != v);            Point.insert(u), ++ n;            for (int x : Point) for (int v : G[x])                if ((bool)Point.count(v)) ++ m;            m >>= 1;            if (m < n) (ans *= k) %= Mod;            if (m == n) (ans *= Polya(n)) %= Mod;            if (m > n) (ans *= Permu(m)) %= Mod;        }    } else chkmin(lowlink[u], dfn[v]);    if (!fa) -- top;}int main () {    File();    n = read(), m = read(); k = read();    Init(m + k + 5);    For (i, 1, m) {        int u = read(), v = read();        G[u].push_back(v);        G[v].push_back(u);    }    For (i, 1, n) if (!dfn[i]) Tarjan(i, 0);    printf ("%lld\n", ans);    return 0;}

ARC062 - F. Painting Graphs with AtCoDeer (Polya+點雙聯通分量)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.