ARC 062 F - Painting Graphs with AtCoDeer 割點 割邊 不動點 burnside引理
阿新 • • 發佈:2020-07-25
LINK:Painting Graphs with AtCoDeer
看英文題面果然有點吃不消 一些細節會被忽略掉。
問每條邊都要被染色 且一個環上邊的顏色可以旋轉.
用c種顏色有多少本質不同的方法。
注意這裡的環指簡單環 即不能經過一個節點兩次。
考慮環套環的情況 手玩可以發現 可以將這種情況出現的所有邊按順序放置。
那麼只和顏色出現的次數有關 隔板法做即可。
一個環 容易發現可以使用burnside引理。
割邊 也很容易。
難點是求簡單環。
不能求割邊 因為邊雙不一定是簡單環。
但是點雙可以發現是簡單環 證明可以感性理解 我也不知道怎麼證明。
再跑個割邊求就複雜了。這道題特殊性是 無重邊無自環。
割邊所屬的那兩個點顯然是一個點雙 所以這道題中大小為2的點雙中間夾的就是割邊。
複雜度\(n^2log\)
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; }