• [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-1choose 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 }
    View Code
  • 相关阅读:
    数学模型(第五版) 姜启源、谢金星、叶俊 版 课后答案 高等教育出版社 训练题答案 课后习题答案
    网络编程释疑之:同步,异步,阻塞,非阻塞
    Linux ssh黄金参数
    linux下安装java
    C/C++字符串和其他类型转换
    C语言获取当前时间
    C语言字符串复制
    C语言文件读写操作
    C语言实现读取文件所有内容到字符串
    AES加密的C语言实现
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14462860.html
Copyright © 2020-2023  润新知