[atARC062F]Painting Graphs with AtCoDeer
求出点双后缩点,对于点双之间,显然不存在简单环,即每一个简单环一定在一个点双内部,换言之即每一个点双可以独立的考虑,然后将结果相乘
(对于点双之间的边任意染色,即若有$s$条边,还会有$k^{s}$的贡献)
对点双分类讨论(假设其有$n$个节点,$m$条边):
1.$n=2$且$m=1$(也就是两点一边),贡献为$k$
2.$n=m$(一个环),根据polya定理,贡献即$\frac{\sum_{i=0}^{n-1}k^{\gcd(n,i)}}{n}$
3.$n<m$,则任意两边的颜色都可以单独交换(其他边的颜色不变),即仅关心每种颜色的边的数量,根据插板法,贡献即${m+k-1\choose k-1}$
关于第3类中任意两边的颜色可以单独交换,下面来证明一下:
更方便的,由于整个连通,那么原结论等价于可以单独交换有公共端点的两条边
简单分析,可以发现这两条边必然会属于一个简单环$R_{1}$,且$R_{1}$与另一个简单环$R_{2}$有公共边
先通过在$R_{1}$上轮换,使得其中恰好有一条边属于公共边的部分,另一条边仅属于$R_{1}$
接下来,将这两条边单独交换,然后再轮换返回原来的位置
具体来说,先轮换$R_{2}$使得原本在公共边上的边仅属于$R_{2}$,再轮换$R_{1}$使得原本在$R_{1}$中的边在公共边上,再轮换$R_{1}$和$R_{2}$除去公共边的部分,可以发现就完成了交换
(更形象地,可以参考atcoder题解中第3页的4幅图)
时间复杂度为$o(n+m)$,可以通过


1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 55
4 #define mod 1000000007
5 struct Edge{
6 int nex,to;
7 }edge[N<<2];
8 stack<int>st;
9 vector<int>v[N];
10 int bcc,E,n,m,k,x,y,ans,head[N],dfn[N],low[N],vis[N];
11 int gcd(int x,int y){
12 if (!y)return x;
13 return gcd(y,x%y);
14 }
15 int pow(int n,int m){
16 int s=n,ans=1;
17 while (m){
18 if (m&1)ans=1LL*ans*s%mod;
19 s=1LL*s*s%mod;
20 m>>=1;
21 }
22 return ans;
23 }
24 void add(int x,int y){
25 edge[E].nex=head[x];
26 edge[E].to=y;
27 head[x]=E++;
28 }
29 void dfs(int k,int fa){
30 if (fa)st.push(k);
31 dfn[k]=low[k]=++dfn[0];
32 for(int i=head[k];i!=-1;i=edge[i].nex)
33 if (edge[i].to!=fa){
34 if (dfn[edge[i].to])low[k]=min(low[k],dfn[edge[i].to]);
35 else{
36 dfs(edge[i].to,k);
37 low[k]=min(low[k],low[edge[i].to]);
38 if (low[edge[i].to]>=dfn[k]){
39 while (1){
40 v[bcc].push_back(st.top());
41 st.pop();
42 if (v[bcc].back()==edge[i].to)break;
43 }
44 v[bcc++].push_back(k);
45 }
46 }
47 }
48 }
49 int main(){
50 scanf("%d%d%d",&n,&m,&k);
51 memset(head,-1,sizeof(head));
52 for(int i=1;i<=m;i++){
53 scanf("%d%d",&x,&y);
54 add(x,y);
55 add(y,x);
56 }
57 for(int i=1;i<=n;i++)
58 if (!dfn[i])dfs(i,0);
59 ans=1;
60 for(int i=0;i<bcc;i++){
61 int nn=v[i].size(),mm=0,s=0;
62 memset(vis,0,sizeof(vis));
63 for(int j=0;j<v[i].size();j++)vis[v[i][j]]=1;
64 for(int j=0;j<v[i].size();j++)
65 for(int k=head[v[i][j]];k!=-1;k=edge[k].nex)
66 if (vis[edge[k].to])mm++;
67 mm/=2;
68 if ((nn==2)&&(mm==1))s=k;
69 else{
70 if (nn==mm){
71 for(int j=0;j<nn;j++)s=(s+pow(k,gcd(nn,j)))%mod;
72 s=1LL*s*pow(nn,mod-2)%mod;
73 }
74 else{
75 s=1;
76 for(int j=mm+1;j<mm+k;j++)s=1LL*s*j%mod;
77 for(int j=1;j<k;j++)s=1LL*s*pow(j,mod-2)%mod;
78 }
79 }
80 ans=1LL*ans*s%mod;
81 }
82 printf("%d",ans);
83 }
[atARC062F]Painting Graphs with AtCoDeer的更多相关文章
- [Arc062] Painting Graphs with AtCoDeer
[Arc062] Painting Graphs with AtCoDeer Description 给定一张N点M边的无向图,每条边要染一个编号在1到K的颜色.你可以对一张染色了的图进行若干次操作, ...
- ARC 062 F - Painting Graphs with AtCoDeer 割点 割边 不动点 burnside引理
LINK:Painting Graphs with AtCoDeer 看英文题面果然有点吃不消 一些细节会被忽略掉. 问每条边都要被染色 且一个环上边的颜色可以旋转. 用c种颜色有多少本质不同的方法. ...
- AtcoderARC062F Painting Graphs with AtCoDeer 【双连通分量】【polya原理】
题目分析: 如果一个双连通分量是简单环,那么用polya原理计数循环移位即可. 如果一个双连通分量不是简单环,那么它必然可以两两互换,不信你可以证明一下相邻的可以互换. 如果一条边是桥,那么直接乘以k ...
- ARC062 - F. Painting Graphs with AtCoDeer (Polya+点双联通分量)
似乎好久都没写博客了....赶快来补一篇 题意 给你一个 \(n\) 个点 , 没有重边和自环的图 . 有 \(m\) 条边 , 每条边可以染 \(1 \to k\) 中的一种颜色 . 对于任意一个简 ...
- 2018.09.20 atcoder Painting Graphs with AtCoDeer(tarjan+polya)
传送门 一道思维题. 如果没有环那么对答案有k的贡献. 如果恰为一个环,可以用polya求贡献. 如果是一个有多个环重叠的双联通的话,直接转化为组合数问题(可以证明只要每种颜色被选取的次数相同一定可以 ...
- 【AtCoder】ARC062F - AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer
题解 考虑一个点双(因为是简单环),如果没有环(两点一线),那么乘上K 如果有一个环,那么用polya定理,每个置换圈有gcd(i,n)个循环节 如果有两个及以上的环,任何一种置换都合法,那么只和每个 ...
- [ARC062F]Painting Graphs with AtCoDeer
题意:一个无向图,用$k$种不同的颜色给每条边染色,问能染出多少种不同的图,如果两张图能通过循环移位环边使得颜色相同,那么这两张图被认为是相同的 数学太差伤不起啊...补了一下Burnside定理的证 ...
- 【ARC062F】 Painting Graphs with AtCoDeer 点双连通分量+polya定理
Description 给定一张N点M边的无向图,每条边要染一个编号在1到K的颜色. 你可以对一张染色了的图进行若干次操作,每次操作形如,在图中选择一个简单环(即不经过相同点的环),并且将其颜色逆时针 ...
- ARC062F AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer Burnside 引理
题目传送门 https://atcoder.jp/contests/arc062/tasks/arc062_d 题解 首先对整张图做 Tarjan 点双. 对于一个点双,如果是由一条边构成的,那么很显 ...
随机推荐
- 记录一次基于VuePress + Github 搭建个人博客
最终效果图 网站:https://chandler712.github.io/ 一.前言 VuePress 是尤雨溪推出的支持 Vue 及其子项目的文档需求而写的一个项目,UI简洁大方,官方文档详细容 ...
- 双指针之滑动窗口(长度最小的子数组 和 和为s的连续正数序列)
双指针之滑动窗口 (长度最小的子数组:和为s的连续正数序列) 1, 什么时候使用? (与子数组/字符串 有关的题目)~如果给了某个具体值的target,即用滑动窗口 不然就双指针(一般做法,左边< ...
- $\Large{\LaTeX}$ 常用公式
$$\Large{\LaTeX}$$: \[\Large{\LaTeX} \] $ $ 表示行内 $$ $$ 表示独立 $\operatorname{lcm}(x)$\(\operatorname{l ...
- Jenkins 进阶篇 - 单元测试覆盖率
我们做项目开发,肯定免不了要写单元测试,不管是 Java 项目.Python 项目.PHP 项目,甚至是 nodejs 项目,都应该要写单元测试,本小节就来介绍单元测试的覆盖率报告输出和展示,在后面的 ...
- Mybatis 二级缓存应用 (21)
[MyBatis 二级缓存] 概述:一级缓存作用域为同一个SqlSession对象,而二级缓存用来解决一级缓存不能夸会话共享,作用范围是namespace级,可以被多个SqlSession共享(只要是 ...
- python使用Django框架开发简单项目
一. (1)使用idea生成一个python项目,安装Django框架: pip install django==1.8.2 (2)初始化项目: django-admin startproject x ...
- PHP文件上传漏洞与一句话木马
靶子代码: 前端效果: 这是个没有任何防护的文件上传代码,同时还热心的附上了上传文件的路径. 我们写好php木马后,什么额外工作也不需要做,直接上传就行了.上传后在浏览器里访问该文件,其就会被执行. ...
- Netty学习笔记(1)NIO三大组件
1. Channel channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前 ...
- 用cmd命令行创建vue项目模板
1.进入cmd命令行 输入存放项目的位置 2.通过vue create 项目名称 创建项目 3.选择Manually select features 4.通过空格选中第1.2.5.6.7.去掉8 4. ...
- [CPP] 类的内存布局
本文可以解决下面 3 个问题: 以不同方式继承之后,类的成员变量是如何分布的? 虚函数表及虚函数表指针,在可执行文件中的位置? 单一继承.多继承.虚拟继承之后,类的虚函数表的内容是如何变化的? 在这里 ...