【sgu282】Isomorphism

题意:

给出n(n<=53)点的无向完全图 要将每条边染上m(m<=1000)种颜色的一种

只改变顶点编号的图视为同种方案 求本质不同方案数%p(p>n且为质树)的值

题解:

这题貌似是很裸的polya 但是发现置换有n!个 根本枚举不出来 于是我们采用算每个点置换对应的边轮换相加得到答案 注意:这里的点置换并不是指原图中的点 而是某条边的两个顶点
假设现在知道一个点置换P=(1)^c1(2)^c2(3)^c3... P对应的边轮换有两种
1.边的两个顶点在同一个点轮换里 设点轮换长度为L 这个点轮换对应的边轮换有L/2个 这种总的有∑(i/2*ci)个
2.边的两个顶点在不同的点轮换里 设点轮换长度为L1、L2 这两个点轮换对应的边轮换有***(L1,L2)个
证明:置换长度为L1*L2 轮换长度为lcm(L1,L2) 边轮换=L1*L2/lcm(L1,L2)=***(L1,L2)
这种总数有 分为两种情况:
(1)L1=L2 有∑(***(i,i)*C(ci,2))=∑(i*ci*(ci-1)/2)个
(2)L1≠L2 有∑(***(i,j)*ci*cj)个
所以一个点置换对应的边轮换个数有 ∑(i/2*ci)+∑(i*ci*(ci-1)/2)+∑(***(i,j)*ci*cj)个
点置换的求法:知道∑(i*ci)=n 用dfs枚举ci即可 知道指定的{ci} 边置换个数是相同的 只要再*共轭类就行了
知道边置换只要套一下polya就完了 因为它的p是给出的 且大于n 所以***(p,n!)=1 所以n!的乘法逆元为n!^(p-2)
这题也有点会卡常数 但是没spoj那么凶残 ci的值需要开个栈记下了 不然可能会TLE 另外 这题虽然开long long没关系 但是有些连乘的地方要%多次 不然long long也会爆

代码:

 1 #include <cstdio>
 2 typedef long long ll;
 3 ll n,m,p,ans,add[60][2],jc[61],top;
 4 ll gcd(ll a,ll b){
 5           ll t;
 6           while (b) t=a,a=b,b=t%b;
 7           return a;
 8 }
 9 ll mi(ll a,ll b){
10          ll res=1;
11          for (;b;b>>=1){
12              if (b&1) res=res*a%p;
13              a=a*a%p;
14          }
15          return res;
16 }
17 ll gon2(){
18           ll save=1;
19           for (ll i=1;i<=top;i++)
20           save=(save*jc[add[i][0]]%p*mi(add[i][1],add[i][0]))%p;
21           return jc[n]*mi(save,p-2)%p;
22 }
23 void work(){
24      ll tot=0;
25      for (ll i=1;i<=top;i++){
26          tot+=(add[i][1]/2)*add[i][0];
27          if (add[i][0]>1) tot+=add[i][1]*add[i][0]*(add[i][0]-1)/2;
28          for (ll j=i+1;j<=top;j++) tot+=gcd(add[i][1],add[j][1])*add[i][0]*add[j][0];
29      }
30      ans=(ans+mi(m,tot)*gon2())%p;
31 }
32 void dfs(ll t,ll r){
33      if (t>r){
34               if (!r) work();
35               return;
36      }
37      for (ll i=0;i*t<=r;i++){
38          if (i) add[++top][0]=i,add[top][1]=t;
39          dfs(t+1,r-i*t);
40          if (i) --top;
41      }
42 }
43 void extgcd(ll a,ll b,ll &x,ll &y){
44      if (!b) x=1,y=0;
45      else{
46           extgcd(b,a%b,x,y);
47           ll t=x;
48           x=y;
49           y=t-a/b*y;
50      }
51 }
52 void makejc(){
53      jc[0]=1;
54      for (ll i=1;i<=60;i++) jc[i]=jc[i-1]*i%p;
55 }
56 int main(){
57     freopen("sgu282.in","r",stdin);
58     freopen("sgu282.out","w",stdout);
59     scanf("%I64d %I64d %I64d
",&n,&m,&p);
60     makejc();
61     dfs(1,n);
62     printf("%I64d",ans*mi(jc[n],p-2)%p);
63     fclose(stdin);
64     fclose(stdout);
65 }
View Code
原文地址:https://www.cnblogs.com/g-word/p/3691770.html