【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",&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

 

你可能感兴趣的:(ISO)