题解

考虑一个点双(因为是简单环),如果没有环(两点一线),那么乘上K
如果有一个环,那么用polya定理,每个置换圈有gcd(i,n)个循环节
如果有两个及以上的环,任何一种置换都合法,那么只和每个颜色用了多少个有关,用插板法算组合数就是\(\binom{n + k - 1}{k - 1}\)

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
//#define ivorysi
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define mo 974711
#define RG register
#define MAXN 200005
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {putchar('-');x = -x;}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
const int MOD = 1000000007;
int N,M,K;
struct node {
    int to,next;
}E[1005];
int head[55],sumE,fac[205],invfac[205],dfn[55],low[55],idx,sta[105],top,col[55],cnt,ans;
vector<int> ver;
int mul(int a,int b) {return 1LL * a * b % MOD;}
int inc(int a,int b) {a = a + b;if(a >= MOD) a -= MOD;return a;}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
    if(c & 1) res = mul(res,t);
    t = mul(t,t);
    c >>= 1;
    }
    return res;
}
int gcd(int a,int b) {
    return b == 0 ? a : gcd(b,a % b);
}
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
int C(int n,int m) {
    if(n < m) return 0;
    return mul(mul(fac[n],invfac[m]),invfac[n - m]);
}
void Tarjan(int u,int fa) {
    dfn[u] = low[u] = ++idx;
    sta[++top] = u;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(v != fa) {
        if(dfn[v]) low[u] = min(low[u],dfn[v]);
        else {
        Tarjan(v,u);
        if(low[v] >= dfn[u]) {
            ver.clear();
            ++cnt;
            col[u] = cnt;
            ver.pb(u);
            while(1) {
            int x = sta[top--];
            col[x] = cnt;
            ver.pb(x);
            if(x == v) break;
            }
            int tot = 0;
            for(auto k : ver) {
            for(int j = head[k] ; j ; j = E[j].next) {
                if(col[E[j].to] == cnt) ++tot;
            }
            }
            tot /= 2;
            if(tot == 1) ans = mul(ans,K);
            else if(tot == ver.size()) {
            int t = 0;
            for(int j = 1 ; j <= tot ; ++j) {
                t = inc(t,fpow(K,gcd(tot,j)));
            }
            t = mul(t,fpow(tot,MOD - 2));
            ans = mul(ans,t);
            }
            else ans = mul(ans,C(tot + K - 1,K - 1));
        }
        else low[u] = min(low[v],low[u]);
        }
    }
    }
}
void Solve() {
    read(N);read(M);read(K);
    int u,v;
    for(int i = 1 ;i <= M ; ++i) {
    read(u);read(v);add(u,v);add(v,u);
    }
    fac[0] = 1;
    for(int i = 1 ; i <= 200; ++i) fac[i] = mul(fac[i - 1],i);
    invfac[200] = fpow(fac[200],MOD - 2);
    for(int i = 199 ; i >= 0 ; --i) invfac[i] = mul(invfac[i + 1],i + 1);
    ans = 1;
    for(int i = 1 ; i <= N ; ++i) {
    if(!dfn[i]) Tarjan(i,0);
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
    return 0;
}
04-26 15:31