分单边,
单环,
复环来讨论。
发现复环中可以交换任意两条边的颜色,直接组合数即可。
单环用burnside引理。
单边直接乘。
A C C o d e \rm AC \ Code AC Code
#define maxn 55
#define maxm 205
#define mod 1000000007
using namespace std;
int n,m,k;
int info[maxn],Prev[maxm],to[maxm],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int dfn[maxn],low[maxn],sta[maxn],tot,fac[maxm]={1,1},inv[maxm]={1,1},invf[maxm]={1,1};
int vis[maxn],tim;
vector<vector<int> >pd;
void dfs(int u){
dfn[u] = low[u] = ++tot;sta[++sta[0]] = u;
for(int i=info[u],v;i;i=Prev[i]) if(!dfn[v=to[i]]){
dfs(v);
if(low[v] >= dfn[u]){
vector<int>p;p.push_back(u);
for(int t = -1;t!=v;)
p.push_back(t = sta[sta[0]--]);
pd.push_back(p);
}
low[u] = min(low[u] , low[v]);
}else low[u] = min(low[u] , dfn[v]);
}
int Pow(int base,int k){
int ret = 1;
for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
return ret;
}
int C(int a,int b){ return 1ll * fac[a] * invf[b] % mod * invf[a-b] % mod; }
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),Node(u,v),Node(v,u);
for(int i=2;i<maxm;i++)
fac[i] = 1ll * fac[i-1] * i % mod,
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod ,
invf[i] = 1ll * invf[i-1] * inv[i] % mod;
for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
int ans = 1;
for(auto U:pd){
++tim;
for(int u:U) vis[u] = tim;
int cnt = 2*U.size();
for(int u:U) for(int i=info[u],v;i;i=Prev[i])
if(vis[v=to[i]]==tim) cnt--;
if(cnt>0) ans = 1ll * ans * k % mod;
else if(cnt == 0){
int sum = 0;
for(int i=1;i<=U.size();i++)
sum = (sum + Pow(k,__gcd((int)U.size(),i))) % mod;
ans = 1ll * ans * sum % mod * Pow(U.size(),mod-2) % mod;
}else ans = 1ll * ans * C(U.size()-cnt/2+k-1,k-1) % mod;
}
printf("%d\n",(ans+mod)%mod);
}