zoukankan      html  css  js  c++  java
  • [Arc062] Painting Graphs with AtCoDeer

    [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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    C++中整型变量的存储大小和范围
    A1038 Recover the Smallest Number (30 分)
    A1067 Sort with Swap(0, i) (25 分)
    A1037 Magic Coupon (25 分)
    A1033 To Fill or Not to Fill (25 分)
    A1070 Mooncake (25 分)
    js 获取控件
    C#代码对SQL数据库添加表或者视图
    JS 动态操作表格
    jQuery取得下拉框选择的文本与值
  • 原文地址:https://www.cnblogs.com/wxjor/p/9470947.html
Copyright © 2011-2022 走看看