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

LINK:Painting Graphs with AtCoDeer

看英文题面果然有点吃不消 一些细节会被忽略掉。

问每条边都要被染色 且一个环上边的颜色可以旋转.

用c种颜色有多少本质不同的方法。

注意这里的环指简单环 即不能经过一个节点两次。

考虑环套环的情况 手玩可以发现 可以将这种情况出现的所有边按顺序放置。

那么只和颜色出现的次数有关 隔板法做即可。

一个环 容易发现可以使用\(burnside\)引理。

割边 也很容易。

难点是求简单环。

不能求割边 因为边双不一定是简单环。

但是点双可以发现是简单环 证明可以感性理解 我也不知道怎么证明。

再跑个割边求就复杂了。这道题特殊性是 无重边无自环。

割边所属的那两个点显然是一个点双 所以这道题中大小为2的点双中间夹的就是割边。

复杂度\(n^2logn\)

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 10000000000000000ll
#define inf 1000000000
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-10
#define sq sqrt
#define S second
#define F first
#define mod 1000000007
using namespace std;
char *fs,*ft,buf[1<<15];
inline char gc()
{
	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
	RE int x=0,f=1;RE char ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
	return x*f;

}
const int MAXN=55,maxn=110<<2;
int n,m,c,len=1,maxx,top,cc,cnt,T,ans=1;
int fac[maxn],inv[maxn],vis[maxn],mark[maxn],dfn[maxn],low[maxn],s[maxn],g[maxn],q[maxn];
int lin[MAXN],ver[maxn],nex[maxn];
inline void add(int x,int y)
{
	ver[++len]=y;
	nex[len]=lin[x];
	lin[x]=len;
}
inline int ksm(int b,int p)
{
	int cnt=1;
	while(p)
	{
		if(p&1)cnt=(ll)cnt*b%mod;
		b=(ll)b*b%mod;p=p>>1;
	}
	return cnt;
}
inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline int solve(int n)
{
	int sum=0;
	rep(1,n,i)sum=(sum+ksm(c,gcd(n,i)))%mod;
	sum=(ll)sum*ksm(n,mod-2)%mod;
	return sum;
}
inline int C(int a,int b){return a<b?0:fac[a]*(ll)inv[b]%mod*inv[a-b]%mod;}
inline void solve_1(int n)
{
	if(n==2)return ++cnt,void();
	rep(1,n,i)mark[q[i]]=1;
	int sum=0;
	rep(1,n,j)
	{
		for(int k=lin[q[j]];k;k=nex[k])
		{
			int tn=ver[k];
			if(mark[tn])++sum;
		}
	}
	sum=sum>>1;
	if(sum==n)ans=(ll)ans*solve(n)%mod;
	else ans=(ll)ans*C(c+sum-1,c-1)%mod;
	rep(1,n,j)mark[q[j]]=0;
}
inline void dfs(int x)
{
	dfn[x]=low[x]=++T;s[++top]=x;
	go(x)
	{
		if(!dfn[tn])
		{
			dfs(tn);
			low[x]=min(low[x],low[tn]);
			int tt=0;
			if(low[tn]>=dfn[x])
			{
				int y=0;tt=0;
				while(y!=tn)
				{
					y=s[top--];
					q[++tt]=y;
				}
				q[++tt]=x;
				solve_1(tt);
			}
		}
		else low[x]=min(low[x],dfn[tn]);
	}
}
int main()
{
	//freopen("1.in","r",stdin);
	maxx=300;get(n);get(m);get(c);
	rep(1,m,i)
	{
		int get(x),get(y);
		add(x,y);add(y,x);
	}
	fac[0]=1;
	rep(1,maxx,i)fac[i]=(ll)fac[i-1]*i%mod;
	inv[maxx]=ksm(fac[maxx],mod-2);
	fep(maxx-1,0,i)inv[i]=(ll)inv[i+1]*(i+1)%mod;
	rep(1,n,i)if(!dfn[i])dfs(i);
	ans=(ll)ans*ksm(c,cnt)%mod;
	put(ans);return 0;
}
posted @ 2020-07-25 08:54  chdy  阅读(132)  评论(0编辑  收藏  举报