[Arc062] Painting Graphs with AtCoDeer

Description

给定一张N点M边的无向图,每条边要染一个编号在1到K的颜色。你可以对一张染色了的图进行若干次操作,每次操作形如,在图中选择一个简单环(即不经过相同点的环),并且将其颜色逆时针旋转一个单位。形式的说,假设你选择的环上的边按顺序依次是e1, e2, ... ,ek,那么经过一次操作后ei mod n+1的颜色会变成操作前ei的颜色。两种染色方案被认为是本质相同的,当且仅当其中一种染色后

的图经过若干次操作后可以变成另一种染色后的图。问有多少本质不同的染色方案,输出对109+7取模。

Input

第一行三个正整数N M K

接下来M行每行两个正整数表示图中的一条边。

Output

输出一行一个非负整数表示答案。

Sample Input

Sample Input 1

4 4 2

1 2

2 3

3 1

3 4

Sample Input 2

5 2 3

1 2

4 5

Sample Input 3

11 12 48

3 1

8 2

4 9

5 4

1 6

2 9

8 3

10 8

4 10

8 6

11 7

1 8

Sample Output

Sample Output 1

8

Sample Output 2

9

Sample Output 3

569519295

HINT

1≤N≤50

1≤M, K≤100

试题分析

首先对于每条不在任何环中的边,其贡献是\(K\)倍,因为它可以染任意颜色并且不与其它边交换。

那么剩下的就是若干个边互不相交的极大点双联通分量,肯定分别来求。

考虑一个大小为4的环,中间对角线有一条边,那么猜想它的任意两条边都可以交换。

分类讨论证明,即证明如上描述图中的一条长度为3的链,可以任意像大小为3的环那样交换,并证明如上描述图中4环上的一条边能与对角线交换,即可证明可以随意交换。

画个图就是长成下面这个样子:

但是还剩下“裸环”的情况,这就是裸的\(Polya\)定理了,简述一下\(Polya\)定理: $$Ans=\frac{1}{|G|}(m{c(f_1)}+m{c(f_2)} \ldots m{c{f_G}})$$

其中\(c(x)\)即为循环个数,由\(Burnside\)引理中的“不动点”个数求出,“不动点”个数即为循环个数乘上颜色数,因为循环各个独立,只要保证一个循环中所有点都是同种颜色的即可。

另外,\(c(x)=gcd(i,G)\),证明请见:link

对于点双联通分量不是“裸环”的情况组合数隔板法即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<algorithm> using namespace std;
#define LL long long inline LL read(){
LL x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const LL INF = 2147483600;
const LL MAXN = 100010;
const LL Mod = 1e9+7; LL N,M,K; LL cnt;
struct edge{
LL u,v; edge(LL uu=0,LL vv=0){
u=uu; v=vv;
}
}edg[MAXN+1];
LL fac[MAXN+1],ifac[MAXN+1],inv[MAXN+1];
LL Node[MAXN<<1],Next[MAXN<<1],Root[MAXN<<1];
LL sz[MAXN+1]; bool inq[MAXN+1];
vector<edge> vec[MAXN+1];
LL fa[MAXN+1]; bool vis[MAXN+1];
LL tim,col,top; LL q[MAXN+1]; inline LL Pow(LL a,LL b){
LL res=1; for(;b;b>>=1,a=a*a%Mod) if(b&1) res=res*a%Mod; return res;
}
inline void insert(LL u,LL v){
Node[++cnt]=v; Next[cnt]=Root[u]; Root[u]=cnt; return ;
} LL dfn[MAXN+1],low[MAXN+1],sta[MAXN+1];
LL ans=1; inline LL gcd(LL a,LL b){
if(!b) return a; return gcd(b,a%b);
}
inline LL Polya(LL sz){
//cout<<"Polya:"<<sz<<endl;
LL res=0; for(LL i=1;i<=sz;i++) (res+=Pow(K,gcd(i,sz)))%=Mod;
return res*Pow(sz,Mod-2)%Mod;
}
inline LL C(LL n,LL m){
if(n<m) return 0; if(!m) return 1;
return fac[n]*ifac[m]%Mod*ifac[n-m]%Mod;
}
inline void dfs(LL k,LL fa){
dfn[k]=low[k]=++tim; sta[++top]=k;
for(LL x=Root[k];x;x=Next[x]){
LL v=Node[x];
if(v==fa) continue;
if(!dfn[v]){
dfs(v,k); low[k]=min(low[k],low[v]);
if(dfn[k]<=low[v]){
LL tp=0,sz=0; ++col;
memset(vis,false,sizeof(vis));
while(q[tp]!=v){
vis[sta[top]]=1; q[++tp]=sta[top]; --top;
} vis[k]=1; q[++tp]=k;
for(LL j=1;j<=tp;j++)
for(LL x1=Root[q[j]];x1;x1=Next[x1])
if(vis[Node[x1]]) ++sz;
sz>>=1;
if(sz<tp) ans=ans*K%Mod;
else if(tp==sz) ans=ans*Polya(sz)%Mod;
else ans=ans*C(sz+K-1,K-1)%Mod;
}
} else {
low[k]=min(low[k],dfn[v]);
}
} return ;
} int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
N=read(),M=read(),K=read(); //LL ans=1;
fac[0]=1;
for(LL i=1;i<=MAXN;i++) fac[i]=fac[i-1]*i%Mod;
inv[1]=ifac[0]=ifac[1]=1;
for(LL i=2;i<=MAXN;i++) inv[i]=(Mod-(Mod/i))*inv[Mod%i]%Mod,ifac[i]=ifac[i-1]*inv[i]%Mod;
for(LL i=1;i<=M;i++){
LL u=read(),v=read();
insert(u,v); insert(v,u);
edg[i].u=u; edg[i].v=v; //E[u][v]=E[v][u]=true;
}
for(LL i=1;i<=N;i++)
if(!dfn[i]) dfs(i,0);
printf("%lld\n",ans);
return 0;
}

[Arc062] Painting Graphs with AtCoDeer的更多相关文章

  1. ARC 062 F - Painting Graphs with AtCoDeer 割点 割边 不动点 burnside引理

    LINK:Painting Graphs with AtCoDeer 看英文题面果然有点吃不消 一些细节会被忽略掉. 问每条边都要被染色 且一个环上边的颜色可以旋转. 用c种颜色有多少本质不同的方法. ...

  2. ARC062 - F. Painting Graphs with AtCoDeer (Polya+点双联通分量)

    似乎好久都没写博客了....赶快来补一篇 题意 给你一个 \(n\) 个点 , 没有重边和自环的图 . 有 \(m\) 条边 , 每条边可以染 \(1 \to k\) 中的一种颜色 . 对于任意一个简 ...

  3. ARC062F AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer Burnside 引理

    题目传送门 https://atcoder.jp/contests/arc062/tasks/arc062_d 题解 首先对整张图做 Tarjan 点双. 对于一个点双,如果是由一条边构成的,那么很显 ...

  4. AtcoderARC062F Painting Graphs with AtCoDeer 【双连通分量】【polya原理】

    题目分析: 如果一个双连通分量是简单环,那么用polya原理计数循环移位即可. 如果一个双连通分量不是简单环,那么它必然可以两两互换,不信你可以证明一下相邻的可以互换. 如果一条边是桥,那么直接乘以k ...

  5. 2018.09.20 atcoder Painting Graphs with AtCoDeer(tarjan+polya)

    传送门 一道思维题. 如果没有环那么对答案有k的贡献. 如果恰为一个环,可以用polya求贡献. 如果是一个有多个环重叠的双联通的话,直接转化为组合数问题(可以证明只要每种颜色被选取的次数相同一定可以 ...

  6. 【AtCoder】ARC062F - AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer

    题解 考虑一个点双(因为是简单环),如果没有环(两点一线),那么乘上K 如果有一个环,那么用polya定理,每个置换圈有gcd(i,n)个循环节 如果有两个及以上的环,任何一种置换都合法,那么只和每个 ...

  7. [ARC062F]Painting Graphs with AtCoDeer

    题意:一个无向图,用$k$种不同的颜色给每条边染色,问能染出多少种不同的图,如果两张图能通过循环移位环边使得颜色相同,那么这两张图被认为是相同的 数学太差伤不起啊...补了一下Burnside定理的证 ...

  8. 【ARC062F】 Painting Graphs with AtCoDeer 点双连通分量+polya定理

    Description 给定一张N点M边的无向图,每条边要染一个编号在1到K的颜色. 你可以对一张染色了的图进行若干次操作,每次操作形如,在图中选择一个简单环(即不经过相同点的环),并且将其颜色逆时针 ...

  9. [atARC062F]Painting Graphs with AtCoDeer

    求出点双后缩点,对于点双之间,显然不存在简单环,即每一个简单环一定在一个点双内部,换言之即每一个点双可以独立的考虑,然后将结果相乘 (对于点双之间的边任意染色,即若有$s$条边,还会有$k^{s}$的 ...

随机推荐

  1. java===java基础学习(9)---方法参数

    方法参数注意三要点: 一个方法不能修改一个基本数据类型的参数(数值型或者布尔型). 一个方法可以改变一个对象参数的状态. 一个方法不能让对象参数引用一个新的对象. package testbotoo; ...

  2. 仿照linux dpm机制,实现自己的dpm【转】

    转自:http://blog.csdn.net/lixiaojie1012/article/details/23788713 前边我们讨论分析了linux 内核的dpm实现,分析的目的在于学以致用:在 ...

  3. 使用 ftrace 调试 Linux 内核【转】

    转自:http://blog.csdn.net/adaptiver/article/details/7930646 使用 ftrace 调试 Linux 内核,第 1 部分 http://blog.c ...

  4. Kotlin 学习使用之旅(二)

    为什么从二开始呢?再此之前已经有了一篇了,那是刚知道kotlin的时候草(chao)来(chao)的并且学习一篇, 这次是自己在项目中正式使用并且遇到的一些问题记录,供kotlin新入门的童鞋参考,避 ...

  5. 计数排序的实现--适用于元素均较小的seq

    今天无聊就打算把所有的排序算法都看一遍... 计数排序的时间复杂度是O(n),在算法导论中,用决策树模型中论证了,比较排序的情况为nlogn的复杂度.而计数排序的时间复杂度小于他的原因就是它不需要进行 ...

  6. 【NOIP2016】补题

    今天突然想到自己居然还没把NOIP2016补完 简直是傻逼... 所以开始写 D1T1:模拟 D1T2:NOIP最难的一道题,首先求LCA 离线下,把观察员单独提出来 然后可以维护一个类似桶排序的东西 ...

  7. 使用IDEA从github中下载fastdfs-client-java

    由于在pom文件中加入依赖坐标无法将fastdfs-client-java下载下来,后来通过查资料,发现在中央仓库中没有定义该坐标.为此,使用idea从github下载fastdfs-client-j ...

  8. 实现点击页面其他地方,隐藏div(vue)

    方法一: 通过监听事件 document.addEventListener('click',function(e){ if(e.target.className!='usermessage'){ th ...

  9. Leetcode 之Regular Expression Matching(31)

    正则表达式的匹配,还是挺难的.可根据下一个字符是不是*分为两种情况处理,需要考虑多种情况. bool isMatch(const char *s, const char *p) { if (*p == ...

  10. 高性能网络服务器--I/O复用 select poll epoll_wait之间的区别

    一.select select采用的是集合的方式,最多只能访问1024个套接字.可读,可写,异常,三种访问,并且采用的是轮训的方式进行每次访问都需要从内核向用户空间拷贝 二.poll poll采用的是 ...