【AT2143】Painting Graphs with AtCoDeer

放个链接:AT2143(翻译在讨论中有,也可以直接到AtCoder去看英文题面)

首先对于一条边,分三种情况讨论:
1、不在任何环上,贡献为 K (废话)。
2、在多个互相有交集的点双连通分量中,设 n 为点双连通分量的大小,(实践得出)通过旋转可以使这个点双连通分量中的任意两条边互换,故贡献为 ( n + K 1 K 1 )
3、在一个单一点双连通分量上(在一个简单环上):由Pólya定理可知贡献为 1 | G | g G K c ( g ) = 1 n i = 0 n K gcd ( i , n ) 其中 | G | = n 为置换群的模, c ( g ) 为置换 g 的循环节个数(这里的置换即一次旋转操作)。
那为啥 c ( g ) = gcd ( i , n ) ?我们的 i 在这里还有一层含义:将置换按旋转格数排序后, i 为顺时针旋转的格数。所以在变换 g i 下,原本位置为 a 的边的位置会变为 ( a + i ) mod n 。因此对于每条原本在 a j 位置的边都需要 l c m ( i , n ) n 次旋转回到原位。而使得 l c m ( i , n ) n 相等的 i 的个数也是 l c m ( i , n ) n ,故循环节的长度为 i l c m ( i , n ) n = n i l c m ( i , n ) = gcd ( i , n )

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<set>
#include<stack>

using namespace std;

const long long p=1000000007ll;
long long ans=1ll,fact[201],invfact[201];
int N,M,K,x,y,idx,low[51],dfn[51];
stack<int> s;
set<int> tmp;
vector<int> point[51];

long long qpow(long long a,int x){
    long long s=1ll;
    while(x){if(x&1)(s*=a)%=p;(a*=a)%=p;x>>=1;}
    return s;
}

inline long long C(int n,int m){return fact[n]*invfact[m]%p*invfact[n-m]%p;}

void dfs(int u,bool root=false){
    low[u]=dfn[u]=++idx;s.push(u);
    for(int v:point[u])if(!dfn[v]){
        dfs(v);low[u]=min(low[u],low[v]);
        if(low[v]==dfn[u]){
            tmp.clear();int cnt=1,siz=0,lst;
            do tmp.insert(lst=s.top()),s.pop(),++cnt;while(lst!=v);tmp.insert(u);
            for(int x:tmp)for(int y:point[x])if(tmp.count(y))++siz;
            if((siz>>=1)<cnt)(ans*=K)%=p;else if(siz==cnt){long long sum=0ll;for(int i=0;i<cnt;++i)(sum+=qpow(K,__gcd(i,cnt)))%=p;(ans*=sum*qpow(cnt,p-2)%p)%=p;}else (ans*=C(siz+K-1,K-1))%=p;
        }
    }else low[u]=min(low[u],dfn[v]);
    if(root)s.pop();
}

int main(){
    scanf("%d%d%d",&N,&M,&K);
    fact[0]=invfact[0]=1ll;for(int i=1;i<=M+K;++i)fact[i]=fact[i-1]*i%p;invfact[M+K]=qpow(fact[M+K],p-2);for(int i=M+K-1;i;--i)invfact[i]=invfact[i+1]*(i+1)%p;
    for(int i=1;i<=M;++i)scanf("%d%d",&x,&y),point[x].push_back(y),point[y].push_back(x);
    for(int i=1;i<=N;++i)if(!dfn[i])dfs(i,true);
    printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/ezoixx174/article/details/81661231