【POJ2888】Magic Bracelet Burnside引理+欧拉函数+矩阵乘法

【POJ2888】Magic Bracelet

题意:一个长度为n的项链,有m种颜色的珠子,有k个限制(a,b)表示颜色为a的珠子和颜色为b的珠子不能相邻,求用m种珠子能串成的项链有多少种。如果一个项链在旋转后与另一个项链相同,则认为这两串珠子是相同的。

$n\le 10^9,m\le 10,k\le \frac{m(m-1)} 2 $

题解:好题。

依旧回顾从Burnside引理到Pólya定理的推导过程。一个置换中的不动点要满足它的所有循环中的点颜色都相同,那么在旋转i次的置换中,循环有gcd(i,n)个,我们规定这些循环的起始点是1,2,...gcd(i,n),由于1,1+i,1+2i...的颜色都与i是一样的,那么我们其实只需要考虑1到gcd(i,n)这段的染色方案数即可。如何统计呢?矩阵乘法!

但是枚举i仍然是行不通的,但我们可以考虑枚举d=gcd(i,n),有多少个i满足gcd(i,n)=d呢?显然是$\varphi({n\over d})$!所以DFS所有n的约数即可。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int P=9973;
int n,m,K,mx,tot,ans;
struct M
{
	int v[12][12];
	int * operator [] (const int &a) {return v[a];}
	M () {memset(v,0,sizeof(v));}
	M operator * (const M &a) const
	{
		M b;
		int i,j,k;
		for(i=1;i<=m;i++)	for(j=1;j<=m;j++)	for(k=1;k<=m;k++)	b.v[i][j]=(b.v[i][j]+v[i][k]*a.v[k][j])%P;
		return b;
	}
}S,T[33];
int cnt[20],p[20];
inline int pm(int x,int y)
{
	int z=1;
	x%=P;
	while(y)
	{
		if(y&1)	z=z*x%P;
		x=x*x%P,y>>=1;
	}
	return z;
}
inline void PM(int y)
{
	for(int i=mx;i>=0;i--)	if(y>=(1<<i))	S=S*T[i],y-=1<<i;
}
void dfs(int x,int d,int phi)
{
	if(x>tot)
	{
		memset(S.v,0,sizeof(S.v));
		int i,j;
		for(i=1;i<=m;i++)	S[i][i]=1;
		PM(d-1);
		for(i=1;i<=m;i++)	for(j=1;j<=m;j++)	if(T[0][i][j])	ans=(ans+phi%P*S[i][j])%P;
		return ;
	}
	int i;
	dfs(x+1,d,phi);
	for(i=1;i<cnt[x];i++)	d*=p[x],phi/=p[x],dfs(x+1,d,phi);
	d*=p[x],phi/=(p[x]-1),dfs(x+1,d,phi);
}
void work()
{
	scanf("%d%d%d",&n,&m,&K);
	ans=tot=0;
	int i,j,a,b,t=n,phi=1;
	for(i=1;i<=m;i++)	for(j=1;j<=m;j++)	T[0][i][j]=1;
	for(i=1;i<=K;i++)
	{
		scanf("%d%d",&a,&b);
		T[0][a][b]=T[0][b][a]=0;
	}
	for(mx=0,i=1;(1<<i)<=n;mx=i++)	T[i]=T[i-1]*T[i-1];
	for(i=2;i*i<=t;i++)	if(t%i==0)
	{
		p[++tot]=i,cnt[tot]=1,phi*=i-1,t/=i;
		while(t%i==0)	cnt[tot]++,phi*=i,t/=i;
	}
	if(t>1)	p[++tot]=t,cnt[tot]=1,phi*=t-1;
	dfs(1,1,phi);
	printf("%d\n",ans*pm(n,P-2)%P);
}
int main()
{
	int cas;
	scanf("%d",&cas);
	while(cas--)	work();
	return 0;
}//4 3 2 0 3 2 1 1 2 3 2 2 1 1 1 2 3 2 3 1 1 1 2 2 2

原文地址:https://www.cnblogs.com/CQzhangyu/p/8227388.html

时间: 2024-10-10 06:18:36

【POJ2888】Magic Bracelet Burnside引理+欧拉函数+矩阵乘法的相关文章

Polya 定理入门[Burnside引理,Polya定理,欧拉函数]

$这篇blog重点讨论Polya的应用, 更详细的证明请百度 .$ ___ $Burnside引理$ $$L=\frac{1}{|G|}\sum_{i=1}^{|G|}D(a_i)$$ $L$: 本质不同的方案数. $G$: 置换群集合. $a_i$: 置换群中的第 $i$ 个置换. $D(a_i)$: 进行 $a_i$ 这个置换, 状态不会变化的方案 数量. 该引理与下方内容没有太大关系, 可以暂时忽略. ___ $Problem$ 链接 有 $N$ 个石子围成一圈, 使用 $M$ 种颜色染色

poj-2888 Magic Bracelet

题意: 给出n个珠子的项链和m种珠子: 珠子之间有k对关系,这些珠子不能相邻: 无法通过旋转变成相同的项链视为本质不同: 求本质不同的项链个数,答案对9973取模: n<=10^9,gcd(n,9973)=1,m<=10: 题解: 这显然是一个置换计数的问题: 上burnside引理还是选择poi? 上burnside引理,因为poi定理对颜色的限制要很宽泛才行! 先考虑一种置换姿势,旋转x个珠子: 那么就将项链分成了gcd(x,n)大小的段,而要求的不变置换数要求这些段完全相同: 问题就是求

【数论】欧拉函数

欧拉函数φ      欧拉定理是用来阐述素数模下,指数同余的性质.      欧拉定理:对于正整数N,代表小于等于N的与N互质的数的个数,记作φ(N)      例如φ(8)=4,因为与8互质且小于等于8的正整数有4个,它们是:1,3,5,7     欧拉定理还有几个引理,具体如下:     ①:如果n为某一个素数p,则φ(p)=p-1;     ①很好证明:因为素数p的质因数只有1和它本身,p和p不为互质,所以φ(p)=p-1:     ②:如果n为某一个素数p的幂次,那么φ(p^a)=(p-

数论-欧拉函数

题目1 : 数论五·欧拉函数 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho有时候会用密码写信来互相联系,他们用了一个很大的数当做密钥.小Hi和小Ho约定了一个区间[L,R],每次小Hi和小Ho会选择其中的一个数作为密钥. 小Hi:小Ho,这次我们选[L,R]中的一个数K. 小Ho:恩,小Hi,这个K是多少啊? 小Hi:这个K嘛,不如这一次小Ho你自己想办法算一算怎么样?我这次选择的K满足这样一个条件: 假设φ(n)表示1..n-1中与n互质的数的个

欧拉函数

void Euler_Sieve_Method(int * euler, int n) { euler[1] = 1; for (int i = 2; i < n; i++) { euler[i] = i; } for (int i = 2; i < n; i++) { if (euler[i] == i) { for (int j = i; j < n; j += i) { euler[j] = euler[j] / i * (i - 1); } } } } void Euler_Si

hdu1695(莫比乌斯)或欧拉函数+容斥

题意:求1-b和1-d之内各选一个数组成数对,问最大公约数为k的数对有多少个,数对是有序的.(b,d,k<=100000) 解法1: 这个可以简化成1-b/k 和1-d/k 的互质有序数对的个数.假设b=b/k,d=d/k,b<=d.欧拉函数可以算出1-b与1-b之内的互质对数,然后在b+1到d的数i,求每个i在1-b之间有多少互质的数.解法是容斥,getans函数参数的意义:1-tool中含有rem位置之后的i的质因子的数的个数. 在 for(int j=rem;j<=factor[i

欧拉函数常用性质

欧拉函数定义:设n 为正整数,则1,2......,n中与n互质的整数个数记作f(n). 1.1 若n为素数,f(n)=n-1; 1.2 整数n=p*q,p,q为不同素数,则f(n)=f(p)*f(q)=(p-1)*(q-1) 1.3 n=p^a*q^b,f(n)=f(p^a)*f(q^b)=n*(1-1/p)*(1-1/q) 1.4 分解质因子相乘,f(n)=n*(1-1/p1)*(1-1/p2)*.......*(1-1/pk). f(100)=f(2^2*5^2)=100*1/2*4/5=

POJ2478(SummerTrainingDay04-E 欧拉函数)

Farey Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16927   Accepted: 6764 Description The Farey Sequence Fn for any integer n with n >= 2 is the set of irreducible rational numbers a/b with 0 < a < b <= n and gcd(a,b)

POJ 2478 欧拉函数(欧拉筛法) HDU 1576 逆元求法

相关逆元求法,我之前有写过,还有欧拉函数的求法,欧拉函数与逆元的关系  点击 POJ 2478 又是一个打表的题目,一眼看出结果就是前n个欧拉函数值的和. 这里直接计算欧拉函数值求和会超时,看见多组数据. 然后就是计算欧拉函数,打表就好了. #include <stdio.h> #include <string.h> #include <iostream> using namespace std; typedef long long LL; const int N =