P4727 [HNOI2009] 图的同构计数 和 P4128 [SHOI2006] 有色图 题解
0x00 Burnside's lemma
这里需要一点群论的知识,设
- 其中
X/G 表示集合X 在群G 作用下的本质不同元素集合,那么\left|X/G\right| 则表示本质不同元素个数,即轨道数。 -
-
对于这个题来说
若两个图同构,说明可以通过重标号一个图的方式得到另一个图,所以说
0x01 计算 \left|X^g\right|
假设有一个
0x02 计算 k
寻找等价类的过程就是从某一条边
设当有
0x03 统计排列
直接枚举排列显然是不行的,但是发现若排列的置换环长度
现在考虑置换环内部的排列情况,显然就是圆排列,有
把前面提到的式子整理一下:
0x04 扩展问题
这道题中每一个图相当于是对边染色了,出现的染白,没出现的染黑,不妨多搞几个颜色。
于是就得到了 P4128 一题做法。
#include<bits/stdc++.h>
// #define ONLINE_JUDGE
#define INPUT_DATA_TYPE int
#define OUTPUT_DATA_TYPE int
inline __attribute((always_inline)) INPUT_DATA_TYPE read(){register INPUT_DATA_TYPE x=0;register char f=0,c=getchar();while(c<'0'||'9'<c)f=(c=='-'),c=getchar();while('0'<=c&&c<='9')x=(x<<3)+(x<<1)+(c&15),c=getchar();return f?-x:x;}void print(OUTPUT_DATA_TYPE x){if(x<0)x=-x,putchar('-');if(x>9)print(x/10);putchar(x%10^48);return;}
#define INV_DATA_TYPE long long
INV_DATA_TYPE exgcd(INV_DATA_TYPE a,INV_DATA_TYPE b,INV_DATA_TYPE &x,INV_DATA_TYPE &y){
if(!b){
x=1;
y=0;
return a;
}
INV_DATA_TYPE d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
INV_DATA_TYPE inv(INV_DATA_TYPE n,INV_DATA_TYPE p){
INV_DATA_TYPE x,y;
exgcd(n,p,x,y);
x%=p;
return x>=0?x:x+p;
}
long long mod,modp;
int b[70],gcd[70][70],m,p;
long long fact[1000],pwm[100000],res;
void calc(int K){
register int i,j,k=0,cnt=0;
register long long v=1;
b[K]=-1;
for(i=0;i<K;++i){
k+=b[i]>>1;
(v*=b[i])%=mod;
++cnt;
if(b[i]!=b[i+1]){
(v*=fact[cnt])%=mod;
cnt=0;
}
for(j=0;j<i;++j)
k+=gcd[b[i]][b[j]];
}
(res+=inv(v,mod)*pwm[k])%=mod;
}
void dfs(int st,int rst){
if(!rst){
calc(st);
return;
}
for(;b[st]<=rst;++b[st]){
b[st+1]=b[st];
dfs(st+1,rst-b[st]);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("name.in", "r", stdin);
freopen("name.out", "w", stdout);
#endif
register int i,j;
int n=read();
m=read();
modp=(mod=read())-1;
for(i=0;i<=n;++i)
for(j=0;j<=n;++j)
if(i==0||j==0)
gcd[i][j]=i|j;
else{
if(i>=j) gcd[i][j]=gcd[i-j][j];
else gcd[i][j]=gcd[i][j-i];
}
for(fact[0]=i=1;i<=n;++i) fact[i]=fact[i-1]*i%mod;
for(pwm[0]=i=1;i<=n*n;++i) pwm[i]=pwm[i-1]*m%mod;
b[0]=1;
dfs(0,n);
print(res);
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}