bzoj 1815: [Shoi2006]color 有色图 置换群

1815: [Shoi2006]color 有色图

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 136  Solved: 50
[Submit][Status]

Description

Input

输入三个整数N,M,P
1< = N <= 53
1< = M < = 1000
N< P < = 10^ 9

Output

即总数模P后的余数

Sample Input

input 1
3 2 97

Sample Output

output 1
4

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define PROB "graph"
#define MAXE MAXN*MAXN
#define MAXN 66
#define MAXM MAXN*MAXN
typedef long long qword;
int n,m,mod;
struct edge
{
        int x,y;
}e[MAXE];
bool operator < (edge e1,edge e2)
{
        if (e1.x==e2.x)return e1.y<e2.y;
        return e1.x<e2.x;
}
bool vis[MAXN];
int vec[MAXN];
qword sum=0;
int per[MAXM];
int g[MAXN];
qword pow_mod(qword x,qword y)
{
        qword ret=1;
        while (y)
        {
                if (y&1)ret=ret*x%mod;
                x=x*x%mod;
                y>>=1;
        }
        return ret;
}
void init()
{
        int i,j,k;
        int m;
        int x,y;
        for (i=2;i<=n;i++)
        {
                m=0;
                for (j=0;j<i;j++)
                        for (k=j+1;k<i;k++)
                                e[m].x=j,e[m++].y=k;
                for (j=0;j<m;j++)
                {
                        edge et;
                        et.x=min((e[j].x+1)%i,(e[j].y+1)%i);
                        et.y=max((e[j].x+1)%i,(e[j].y+1)%i);
                        per[j]=lower_bound(e,e+m,et)-e;
                }
                for (j=0;j<m;j++)
                {
                        if (~per[j])
                        {
                                g[i]++;
                                x=j;
                                y=per[x];
                                per[x]=-1;
                                while (~per[y]){
                                        x=y;
                                        y=per[x];
                                        per[x]=-1;
                                }
                        }
                }
        }
        return ;
}
int gcd(int x,int y)
{
        return x%y==0?y:gcd(y,x%y);
}
qword fact[MAXN],ufact[MAXN],uval[MAXN];
int gcdv[MAXN][MAXN];
int totv;
void dfs(int s,int b)
{
        if (!s)
        {
                register qword val=1;
                register int res=0,n0=n,i,j;
                for (i=0;i<totv;i++)
                        for (j=i+1;j<totv;j++)
                                res=(res+gcdv[vec[i]][vec[j]])%(mod-1);
                for (i=0;i<totv;i++)
                {
                        res=(res+g[vec[i]])%(mod-1);
                        val=val*fact[n0]%mod*ufact[n0-vec[i]]%mod*ufact[vec[i]]%mod;
                        n0-=vec[i];
                }
                //for (int i=0;i<totv;i++)printf("%d ",vec[i]);printf("\n");
                for (i=0;i<totv;)
                {
                        for (j=i;j<totv && vec[j]==vec[i];j++);
                        val=val*ufact[j-i]%mod;
                        i=j;
                }
                for (i=0;i<totv;i++)
                        val=val*fact[vec[i]]%mod*uval[vec[i]]%mod;
                //printf("val:%d\n",val);
                //printf("res:%d\n",res);
                sum+=pow_mod(m,res)*val%mod;
                sum%=mod;
                return ;
        }
        for (int i=b;i<=s;i++)
        {
                vec[totv++]=i;
                dfs(s-i,i);
                totv--;
        }
}
int main()
{
        freopen("input.txt","r",stdin);
        int i,j,k,x,y,z;
        scanf("%d%d%d",&n,&m,&mod);
        init();
        fact[0]=1;
        for (i=1;i<=n;i++)
                for (j=1;j<=n;j++)
                        gcdv[i][j]=gcd(i,j);
        for (i=1;i<=n;i++)
                fact[i]=fact[i-1]*i%mod;
        for (i=0;i<=n;i++)
                ufact[i]=pow_mod(fact[i],mod-2);
        for (i=1;i<=n;i++)
                uval[i]=pow_mod(i,mod-2);
        dfs(n,1);
        printf("%lld\n",sum*ufact[n]%mod);
}

  也许我的想法和标准的想法还是有那么一点点偏差,但还是能做的,我们考虑将这道题转换为标准的染色问题,由于图的变换可以是点的任意置换,所以说图的置换群是n!个点的置换,注意,是“点的置换”,与“边的染色”,所一我们考虑点与变得关系,最朴素的做法是:枚举n!个排列,对于每个排列,算出边的置换以及置换群个数,同ploya定理做。

  然后考虑到n!的排列个数太慢了。于是考虑到置换的性质,我们可以直接枚举点置换的循环节长度的组成,对于跨越两个长度x,y循环节间的边,循环节长度必定为lcm(x,y),变得个数为x*y,所以循环节个数为gcd(x,y),但是循环节内部的边就比较麻烦,虽然看其他程序这也是一个很简单的式子,但是我不会推,就直接暴力预处理求出循环节数。

  最后通过各种排列组合的公式,算出每一个循环节组成代表的排列个数,这道题就完了。

时间: 2024-10-18 00:14:18

bzoj 1815: [Shoi2006]color 有色图 置换群的相关文章

BZOJ 1815: [Shoi2006]color 有色图 [Polya DFS 重复合并]

传送门 题意: 染色图是无向完全图,且每条边可被染成k种颜色中的一种.两个染色图是同构的,当且仅当可以改变一个图的顶点的编号,使得两个染色图完全相同.问N个顶点,k种颜色,本质不同的染色图个数(模质数N≤53,P<109). 想了一节课和一中午又看了课件 相同类型的循环合并的想法很巧妙 首先,点的置换对应唯一边的置换,我们可以枚举所有点的置换,找出每个置换下边置换的循环有多少个,然后套$Polya$公式 但是复杂度带叹号 我们发现,很多点置换类型是一样的,我们可以对$n$搜索划分来枚举点置换的类

bzoj 1025 [SCOI2009]游戏(置换群,DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1025 [题意] 给定n,问1..n在不同的置换下变回原序列需要的不同排数有多少种. [思路] 对于一个置换,如果分解后的到的循环长度为 A1,A2,A3… 则答案为lcm(A1,A2…)的不同种数,即有多少个不同的lcm满足: A1+A2+A3+…=n lcm=lcm(A1,A2,A3…) 对于A[1..]的lcm, lcm=a1^max{p1}*a2^max{p2}.. 只考虑ma

置换群(等价类计数)

一.定义 群 ??群是啥???我不会啊 置换(\(g\)) ??一个置换是一种运算,代表让物体交换位置的一种方法 置换群(\(G\)) ??顾名思义,由置换构成的群 k不动置换类(\(Z_k\))(稳定化子) ??使元素 \(k\) 不改变位置的群的集合 等价类(\(E_k\))(轨道) ??在置换群 \(G\) 作用下元素 \(k\) 的运动轨迹(一些点的集合) 循环(\(h_g\)) ??在置换 \(g\) 作用下产生的循环 轨道-稳定化子定理 \[|E_k|\times|Z_k|=|G|\

[BZOJ 1025] 游戏 置换群 背包DP

题意 对于一个 $n$ 阶置换群 $A$ , 它的循环节大小分别为 $a_1, a_2, ..., a_m$ , 则有 $\sum_{i = 1} ^ m a_i = n$ . 定义 $f(A)$ 为它的所有循环节的最小公倍数, 即 $f(A) = [a_1, a_2, ..., a_m]$ . 求在所有 $n$ 阶置换群中, $f(A)$ 有多少种取值. $n \le 1000$ . 分析 判断 $K$ 可不可取. $K = \prod_{i = 1} ^ r {s_r} ^ {t_r}$ 可

2017-03-17 Codeforces 441D 置换群,好题 bzoj 4750 思维,按位计算

Codeforces 441D 题意:定义理想序列a[]:对于任意的i有a[i] = i.给出一个1到n的排列p[],可以将排列中的任意两个元素两两交换,定义f(p)为将p变为理想排列的最少交换次数,求将p变成排列q,使得f(q) = m 的最少交换次数和交换方案. tags:才知道置换群,看题解码的.. 使得一个排列有序的最小交换次数 = n - 置换群数目. 置换群,A->B,B->C,C->A,相当于一个轮换.   记住三点: 1.一个大小为L的置换群里面的元素至少且必能互换L-1

【BZOJ】1004: [HNOI2008]Cards(置换群+polya+burnside)

http://www.lydsy.com/JudgeOnline/problem.php?id=1004 学习了下polya计数和burnside引理,最好的资料就是:<Pólya 计数法的应用> --陈瑜希 burnside: $$等价类的个数=\frac{1}{|G|}\sum_{i=1}^{s}D(a_i), a_i \in G$$其中$D(a_i)=a_i置换中染色后不变的方案$ 而polya: $$D(a_i)=k^{C(a_i)},其中C(a_i)是a_i的循环节个数$$证明很简单

【BZOJ 1998】[Hnoi2010]Fsk物品调度 置换群+并查集

置换群的部分水得一比,据说是经典的置换群理论(然而我并不知道这理论是啥).重点就在于怎么求pos!!!容易发现这个东西是这样的:每次寻找pos,先在本环里找,找不到再往下一个环里找,直到找到为止……一开始我想二分或者是set,但是感觉会T,然后想了很久之后想到用并查集:就是维护每一个被占用的位置的下一个位置,因为这个位置被占用之后就会转向下一个位置,当然下一个位置有在环内部和在下一个环里两种情况,这两种情况都我都是用并查集维护的,但是一定要注意,不要把这两种情况写成一个并查集,这样路径压缩之后会

bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序【置换群】

至今都不知道置换群是个什么东西--题解说什么就是什么.jpg 以下来自hzwer:http://hzwer.com/3905.html #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=10005; int n,w[N],a[N],v[N]; struct qwe { int x,id; }b[N]; bool cmp(const qwe &a

Luogu P4128 [SHOI2006]有色图

题意与数据范围 求 \(n\) 个点不同构的简单无向图的数目,答案对 \(997\) 取模 \(A\) 图与 \(B\) 图被认为是同构的是指:\(A\) 图的顶点经过一定的重新标号以后,\(A\) 图的顶点集和边集要完全与 \(B\) 图一一对应 \(0\le n\le 60\) Solution 我们把无向图点的每一种重新排布的方式看作一种置换,则该置换群 \(G\) 的大小显然为 \(n!\) 对于置换群 \(G\) 中的每一个置换 \(g\) ,在 \(g\) 的作用下的不动点即为这样的