题意:
给出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也会爆
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }