Atcoder ARC062F - AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer
Atcoder ARC062F - AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer
題目描述
簡(jiǎn)要題意:給定一個(gè)有標(biāo)號(hào)的無(wú)向圖,你可以給每條邊染上KKK種顏色之一,求本質(zhì)不同的圖的染色方案(兩個(gè)圖本質(zhì)不同定義為不能通過(guò)若干次環(huán)的旋轉(zhuǎn)使這兩個(gè)圖每條邊的染色相同)。
Solution
分類討論:
倘若是一條單邊(不包含在任何環(huán)中),則它的顏色任意,方案數(shù)為KKK。
倘若是一個(gè)單環(huán)(不與其他環(huán)的邊相交),則環(huán)上的顏色要旋轉(zhuǎn)后本質(zhì)不同,經(jīng)典的BurnsideBurnsideBurnside問(wèn)題,設(shè)環(huán)長(zhǎng)為cntcntcnt,則方案數(shù)為∑i=0sz?1kgcd(i,sz)\sum_{i=0}^{sz-1} k^{gcd(i,sz)}∑i=0sz?1?kgcd(i,sz)
倘若是兩個(gè)或以上的環(huán)嵌套,可以發(fā)現(xiàn)環(huán)上的顏色都是可以互換的,兩個(gè)嵌套環(huán)不同,當(dāng)且僅當(dāng)某種顏色的個(gè)數(shù)不同,因此方案數(shù)就是一個(gè)插板法,設(shè)嵌套環(huán)有szszsz條邊,則方案數(shù)為C(sz+K?1,K?1)C(sz+K-1,K-1)C(sz+K?1,K?1)。
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <cassert> #include <string.h> //#include <unordered_set> //#include <unordered_map> //#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B) #define PB(A) push_back(A) #define SIZE(A) ((int)A.size()) #define LEN(A) ((int)A.length()) #define FOR(i,a,b) for(int i=(a);i<(b);++i) #define fi first #define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; } template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll; typedef unsigned long long ull; typedef long double lod; typedef pair<int,int> PR; typedef vector<int> VI;const lod eps=1e-11; const lod pi=acos(-1); const int oo=1<<30; const ll loo=1ll<<62; const int mods=1e9+7; const int MAXN=600005; const int INF=0x3f3f3f3f;//1061109567 /*--------------------------------------------------------------------*/ inline int read() {int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f; } vector<int> e[MAXN],V[MAXN]; int fac[MAXN],inv[MAXN],dfn[MAXN],low[MAXN],stk[MAXN],flag[MAXN],top=0,num=0,DFN=0,n,m,k; inline int quick_pow(int x,int y) {int ret=1;for (;y;y>>=1){if (y&1) ret=1ll*ret*x%mods;x=1ll*x*x%mods;}return ret; } inline void Init(int n) {fac[0]=1; for (int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mods;inv[n]=quick_pow(fac[n],mods-2);for (int i=n-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mods; } inline int upd(int x,int y) { return x+y>=mods?x+y-mods:x+y; } inline int gcd(int x,int y) { return y==0?x:gcd(y,x%y); } inline int C(int x,int y) { return 1ll*fac[x]*inv[y]%mods*inv[x-y]%mods; } inline int Burnside(int n) { int ans=0; for (int i=0;i<n;i++) ans=upd(ans,quick_pow(k,gcd(i,n))%mods); return 1ll*ans*quick_pow(n,mods-2)%mods; } inline void tarjan(int x,int father) {dfn[x]=low[x]=++DFN;stk[++top]=x;for (auto v:e[x]){if (v==father) continue;if (!dfn[v]){tarjan(v,x);upmin(low[x],low[v]);if (low[v]>=dfn[x]){int y;V[++num].PB(x);while (y=stk[top--]){V[num].PB(y);if (y==v) break;}}}else upmin(low[x],dfn[v]);} } int main() {n=read(),m=read(),k=read();Init(m+k);for (int i=1;i<=m;i++){int u=read(),v=read();e[u].PB(v),e[v].PB(u);}for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,0);int ans=1;for (int i=1;i<=num;i++){if (V[i].size()==2) ans=1ll*ans*k%mods;else{int cnt=0;for (int i=1;i<=n;i++) flag[i]=0;for (auto x:V[i]) flag[x]=1;for (auto x:V[i])for (auto v:e[x]) if (flag[v]) cnt++;cnt>>=1;if (cnt==V[i].size()) ans=1ll*ans*Burnside(cnt)%mods;else ans=1ll*ans*C(cnt+k-1,k-1)%mods; // cout<<V[i].size()<<" "<<cnt<<" "<<ans<<endl;}}printf("%d\n",ans);return 0; }總結(jié)
以上是生活随笔為你收集整理的Atcoder ARC062F - AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 戴助听器后头痛头晕怎么回事?
- 下一篇: 四肢发麻和打耳洞耳骨有关系吗?