博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ1478]Sgu282 Isomorphism
阅读量:4596 次
发布时间:2019-06-09

本文共 2997 字,大约阅读时间需要 9 分钟。

Description

给定一个N 个结点的无向完全图( 任意两个结点之间有一条边), 现在你可以用 M 种颜色对这个图的每条边进行染色,每条边必须染一种颜色。 若两个已染色的图,其中一个图可以通过结点重新编号而与另一个图完全相同, 就称这两个染色方案相同。 现在问你有多少种本质不同的染色方法,输出结果 mod P。P 是一个大于N 的质数

Input

仅一行包含三个数,N、M、P。
1≤N≤53,1≤M≤1000

Output

仅一行,为染色方法数 mod P 的结果。

Sample Input

3 4 97

Sample Output

20


polya神题,神题,神题,重要的事情说三遍……

这道题真TM毒瘤,我写了好久,还是不会……只有看题解,不得不说那些大佬真的牛逼。

好,废话不多说,我们进入正题。

这题显然是需要用polya的,但是总置换数到了\(N!\)(我的死因),显然简单的枚举是不可行的,因此我们得换种思想

我们考虑一对点的置换 \(f=i\rightarrow p[i]\)

那么,它对应的对边的置换就是 \(f'=(i,j)\rightarrow (p[i],p[j])\)

我们考虑这两个不同类型的置换各自的循环节个数\(c(f)\)\(c(f')\)的关系,便可以得到如下结论:

  • \(i\)和点\(j\)同属于一个长度为\(L\)的循环节中,那么这样的边\((i,j)\)组成的置换中循环节个数显然为\(\lfloor\frac{L}{2}\rfloor\)(考虑隔一个连,隔两个连……即可)
  • \(i\)和点\(j\)各属于长\(L_{i}\)\(L_{j}\)的两个不同循环中,那么这样的边\((i,j)\)组成的循环节的个数为\(lcm(L_{i},L_{j})\)

我们设\(L_{1}\geqslant L_{2}\geqslant ...\geqslant L_{m}>0\),且有\(L_{1}+L_{2}+...+L_{m}=N\),因此,\(L_{i}\)即为\(N\)的一个拆分,而且循环数均为关于\(L_{i}\)的一个函数

由于\(N\leqslant 53\),所以对\(N\)的划分我们可以暴力回溯,然后对于每一种划分我们只要求出对应的置换个数和每个置换的循环节个数

循环节个数我们已知了,置换个数呢?

假定我们已经确定了\(L_{1}\geqslant L_{2}\geqslant ...\geqslant L_{m}>0\),接下来我们只要将\(1...N\)\(N\)个点分别放入这\(m\)个循环节中,满足第\(i\)个循环中有\(L_{i}\)个点,这便是个简单的组合问题,共\(\dfrac{N!}{L_{1}!L_{2}!...L_{m}!}\)种不同的方式

对于每个循环,确定了第一个点,那么剩下的各点的排列所对应的置换也是不同的,所以还要乘上个\((L_{1}-1)!(L_{2}-1)!...(L_{m}-1)!\)

如果有\(L_{i}=L_{i+1}=...=L_{j}\)的话,那么有\((j-i+1)!\)种方案又是重复的,便要除上一个\((j-i+1)!\)

所以置换的个数就是

\[\frac{N!}{L_{1}L_{2}...L_{m}k_{1}!k_{2}!...k_{t}!}\]

其中,\(t\)表示有\(t\)种不同的\(L\)值,每种值有\(k_{i}\)

至此,我们就可以完美地解决这道题了

/*program from Wolfycz*/#include
#include
#include
#include
#include
#define inf 0x7f7f7f7fusing namespace std;typedef long long ll;typedef unsigned int ui;typedef unsigned long long ull;inline int read(){ int x=0,f=1;char ch=getchar(); for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1; for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0'; return x*f;}inline void print(int x){ if (x>=10) print(x/10); putchar(x%10+'0');}const int N=1e3;int fac[N+10],num[N+10],cnt[N+10];int n,m,p,tot,Ans;ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}int mlt(ll a,ll b){ int res=1;a%=p; for (;b;b>>=1,a=1ll*a*a%p) if (b&1) res=1ll*res*a%p; return res;}void dfs(int now,int left){ if (!left){ ll a=1,b=0; for (int i=1;i<=tot;i++){ a=a*mlt(num[i],cnt[i])%p*fac[cnt[i]]%p; //快速计算L和k! b+=cnt[i]*(cnt[i]-1)/2*num[i]+num[i]/2*cnt[i]; //这些数gcd都相同,共有k*(k-1)种组成方法,然后计算在同一个循环节的情况 for (int j=i+1;j<=tot;j++) b+=cnt[i]*cnt[j]*gcd(num[i],num[j]); //计算与之后的点不在同一个循环节的情况 } a=1ll*mlt(a,p-2)*fac[n]%p; Ans=(Ans+1ll*a*mlt(m,b)%p)%p; } if (now>left) return; dfs(now+1,left); //拆分,不选数 for (int i=1;i*now<=left;i++){//拆分,选数 num[++tot]=now,cnt[tot]=i; dfs(now+1,left-i*now); tot--; }}int main(){ n=read(),m=read(),p=read(),fac[0]=1; for (int i=1;i

转载于:https://www.cnblogs.com/Wolfycz/p/8516888.html

你可能感兴趣的文章
关于R软件的安装
查看>>
MySQL数据库免安装版配置
查看>>
你必知必会的SQL面试题
查看>>
html5 Canvas绘制时钟以及绘制运动的圆
查看>>
Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween
查看>>
JavaScript空判断
查看>>
洛谷 P1439 【模板】最长公共子序列(DP,LIS?)
查看>>
python timeit
查看>>
Wireless Network 并查集
查看>>
51nod 1019 逆序数
查看>>
Java_Set用法总结
查看>>
Codeforces Round #160 (Div. 2) D. Maxim and Restaurant(DP)
查看>>
Exchange Port
查看>>
oracle 01578
查看>>
在source中查看代码
查看>>
pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple
查看>>
apache环境下配置多个ssl证书搭建多个站点
查看>>
PHPExcel随笔
查看>>
利用hadoop自带程序运行wordcount
查看>>
语音活性检测器py-webrtcvad安装使用
查看>>