[ARC062]F - Painting Graphs with AtCoDeer 双联通分量+Pólya计数
2018-01-24 21:55
253 查看
题面
把边分成三种:
1. 不在点双联通分量中,直接贡献KK。
2. 在一个环中,记环长为nn,根据Pólya定理,其贡献为1|G|∑g∈GKc(g)=1n∑i=0n−1Kgcd(i,n)(205)(205)1|G|∑g∈GKc(g)=1n∑i=0n−1Kgcd(i,n)
3. 在一个由多个环重叠的点双联通分量中,可以证明可以通过旋转来交换任意两条边的颜色,于是本质不同当且仅当有一种颜色数量不同,其贡献为(n+K−1K−1)(206)(206)(n+K−1K−1)
其实1,2两种情况可以一起考虑。
发现原来并没有写过真正的点双,要么是求割点,要么是边双缩点,要么是仙人掌那种只有环的。。。所以有一下几个要注意的:
1. 显然一个边最多只能在一个点双中,栈中记录的当然是边,但有的边可能正反两次被记录,所以还要记个vis数组。
2. 为了严谨(虽然这题没有重边),但还是最好记录从哪条边来的而不是从哪个点来的。
代码:
把边分成三种:
1. 不在点双联通分量中,直接贡献KK。
2. 在一个环中,记环长为nn,根据Pólya定理,其贡献为1|G|∑g∈GKc(g)=1n∑i=0n−1Kgcd(i,n)(205)(205)1|G|∑g∈GKc(g)=1n∑i=0n−1Kgcd(i,n)
3. 在一个由多个环重叠的点双联通分量中,可以证明可以通过旋转来交换任意两条边的颜色,于是本质不同当且仅当有一种颜色数量不同,其贡献为(n+K−1K−1)(206)(206)(n+K−1K−1)
其实1,2两种情况可以一起考虑。
发现原来并没有写过真正的点双,要么是求割点,要么是边双缩点,要么是仙人掌那种只有环的。。。所以有一下几个要注意的:
1. 显然一个边最多只能在一个点双中,栈中记录的当然是边,但有的边可能正反两次被记录,所以还要记个vis数组。
2. 为了严谨(虽然这题没有重边),但还是最好记录从哪条边来的而不是从哪个点来的。
代码:
#include<iostream> #include<cstdio> #include<cstring> #define chkmin(x,y) x=min(x,y) #define ll long long using namespace std; const int mod=1000000007; int n,m,k,tim,top=0,low[55],dfn[55]; bool vis[55]; ll mi[210],ans=1,fac[210],ifac[210],inv[210]; struct edge { int t;bool vis; edge *next,*rev; }*con[55],*st[110]; void ins(int x,int y) { edge *p=new edge; p->t=y;p->vis=0; p->next=con[x]; con[x]=p; } ll ksm(ll a,int b){ll r=1;for(;b;b>>=1){if(b&1)r=r*a%mod;a=a*a%mod;}return r;} int gcd(int x,int y){return y?gcd(y,x%y):x;} void tarjan(int v,edge *fro) { dfn[v]=low[v]=++tim; for(edge *p=con[v];p;p=p->next) if(!p->vis&&!p->rev->vis) { st[++top]=p;p->vis=p->rev->vis=1; if(!dfn[p->t]) { tarjan(p->t,p); chkmin(low[v],low[p->t]); if(low[p->t]>=dfn[v]) { bool cir=1;int cnt=0;ll cal=0; for(int i=top;st[i+1]!=p;cnt++,i--) if(vis[st[i]->t]) cir=0; else vis[st[i]->t]=1; if(cir) { for(int i=0;i<cnt;i++) cal=(cal+mi[gcd(cnt,i)])%mod; cal=cal*inv[cnt]%mod; } else cal=fac[cnt+k-1]*ifac[cnt]%mod*ifac[k-1]%mod; ans=ans*cal%mod; for(;st[top+1]!=p;top--) vis[st[top]->t]=0; } } else chkmin(low[v],dfn[p->t]); } } int main() { scanf("%d%d%d",&n,&m,&k); mi[0]=1; for(int i=1;i<=m;i++) mi[i]=mi[i-1]*k%mod; fac[0]=1; for(int i=1;i<=m+k;i++) fac[i]=fac[i-1]*i%mod; ifac[m+k]=ksm(fac[m+k],mod-2); for(int i=m+k-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod; for(int i=1;i<=m+k;i++) inv[i]=ifac[i]*fac[i-1]%mod; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y);ins(y,x); con[x]->rev=con[y];con[y]->rev=con[x]; } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,NULL); printf("%lld",ans); return 0; }
相关文章推荐
- 【AtCoder】ARC062F - AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer
- hdu6165 FFF at Valentine 强联通分量+拓扑排序
- 【线段树合并】联通分量计数
- HDU 5631 Rikka with Graph 求从n+1 边中删除一些边使图依然联通
- The Bottom of a Graph POJ - 2553 强联通分量中出度为零的点集
- Codeforces Round #347 (Div. 2) D. Graph Coloring(强联通分量缩点+2-SAT)
- poj 2553 zoj 1979 The Bottom of a Graph(强联通分量 Tarjan)
- 51Nod-1811-联通分量计数
- [HDOJ6165] FFF at Valentine(强联通分量,缩点,拓扑排序)
- POJ 2553 The Bottom of a Graph 缩点之后求出度为0的强联通分量的元素
- Rikka with Graph(联通图取边,暴力)
- [CF711D]Directed Roads(强联通分量,计数)
- 51nod 1811 联通分量计数
- ABAP - 3D Graphs with SAP
- Uva 10601 Cubes(polya计数)
- No resource found that matches the given name (at 'drawab' with value '@drawable/你的资源').
- 【BZOJ2730】【codevs1996】矿场建设,点双联通分量
- Semi-Supervised Classification with Graph Convolutional Networks
- Leetcode Longest Substring with At Most Two Distinct Characters
- Leetcode-159.Longest Substring with At Most Two Distinct Characters