poj 2888 Magic Bracelet (矩阵乘法+置换)

本文探讨了一个关于魔法手链的计数问题,利用矩阵乘法和置换群理论解决特定条件下不同手链方案的数量计算。问题的核心在于如何避免某些类型珠子相邻导致的爆炸,并考虑旋转等价的情况下确定唯一方案的数量。

Magic Bracelet
Time Limit: 2000MS Memory Limit: 131072K
Total Submissions: 5403 Accepted: 1752

Description

Ginny’s birthday is coming soon. Harry Potter is preparing a birthday present for his new girlfriend. The present is a magic bracelet which consists of n magic beads. The are m kinds of different magic beads. Each kind of beads has its unique characteristic. Stringing many beads together a beautiful circular magic bracelet will be made. As Harry Potter’s friend Hermione has pointed out, beads of certain pairs of kinds will interact with each other and explode, Harry Potter must be very careful to make sure that beads of these pairs are not stringed next to each other.

There infinite beads of each kind. How many different bracelets can Harry make if repetitions produced by rotation around the center of the bracelet are neglected? Find the answer taken modulo 9973.

Input

The first line of the input contains the number of test cases.

Each test cases starts with a line containing three integers n (1 ≤ n ≤ 109gcd(n, 9973) = 1), m (1 ≤ m ≤ 10), k (1 ≤ k ≤ m(m − 1) ⁄ 2). The next k lines each contain two integers a and b (1 ≤ ab ≤ m), indicating beads of kind a cannot be stringed to beads of kind b.

Output

Output the answer of each test case on a separate line.

Sample Input

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

Sample Output

4
2
1
0

Source

[Submit]   [Go Back]   [Status]   [Discuss]


题目大意:给n元环染色,求有多少本质不同的染色方案(旋转后相同即算本质相同),且要求a,b颜色不能相连。

题解:矩阵乘法+置换

C(f)要求一个置换中的颜色是必须相同的。这道题计算答案的方式与hdu 2865,主要是f数组的计算方式不同。

我们还是考虑用矩阵来做。把颜色的选择看成生成一条路径,如果a,b颜色不能相连,那么f[a][b]=f[b][a]=0,剩下的都是1,直接进行矩阵。注意统计答案的时候跳过a,b不能相连的位置,因为我们实际形成的应该是个首尾相连的环。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 1000003
#define p 9973
#define LL long long 
using namespace std;
int n,m,T,k;
int phi[N],prime[N],pd[N];
struct data{
	int a[20][20];
}ch,e,b;
void init(int n)
{
	phi[1]=1;
	for (int i=2;i<=n;i++) {
		if (!pd[i]) {
			prime[++prime[0]]=i;
			phi[i]=i-1;
		}
		for (int j=1;j<=prime[0];j++) {
			if (i*prime[j]>n) break;
			pd[i*prime[j]]=1;
			if (i%prime[j]==0) {
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}
int getphi(int x)
{
	if (x<=1000000) return phi[x]%p;
	LL ans=x;
	for (int i=1;prime[i]*prime[i]<=x;i++)
	 if (x%prime[i]==0) {
		ans=(LL)ans/(LL)prime[i]*(LL)(prime[i]-1);
		while (x%prime[i]==0) x/=prime[i];
	}
	if (x>1) ans=(LL)ans/(LL)x*(LL)(x-1);
	return ans%p;
}
void clear(data &a) 
{
	for (int i=1;i<=m;i++)
	 for (int j=1;j<=m;j++) a.a[i][j]=e.a[i][j];
}
data mul(data a,data b)
{
	data c;
	for (int i=1;i<=m;i++)
	 for (int j=1;j<=m;j++) {
	 	c.a[i][j]=0;
	 	int (*w)=&(c.a[i][j]); (*w)=0;
	 	for (int k=1;k<=m;k++) 
	 	 (*w)=((*w)+a.a[i][k]*b.a[k][j])%p;
	 }
	return c;
}
data quickpow(data num,int x)
{
	data ans; clear(ans);
	data base; base=num;
	while (x) {
		if (x&1) ans=mul(ans,base);
		x>>=1;
		base=mul(base,base);
	}
	return ans;
}
int calc(int i)
{
	if (i==1) {
		int ans=0;
		for (int i=1;i<=m;i++) {
		 ans=ans+ch.a[i][i];
		 if (ans>=p) ans-=p;
	    }
		return ans;
	}
	data t=quickpow(ch,i-1);
	int ans=0;
	for (int i=1;i<=m;i++) 
	 for (int j=1;j<=m;j++) 
	  if (ch.a[i][j]) {
	    ans=ans+t.a[i][j];
	    if (ans>=p) ans-=p;
	  }
	return ans;
}
int quickpow(int num,int x)
{
	int ans=1; int base=num%p;
	while (x) {
		if (x&1) ans=ans*base%p;
		x>>=1;
		base=base*base%p;
	}
	return ans;
}
int main()
{
	freopen("a.in","r",stdin);
//	freopen("my.out","w",stdout);
	scanf("%d",&T); init(1000000);
	for (int i=1;i<=10;i++) e.a[i][i]=1;
	while (T--) {
		scanf("%d%d%d",&n,&m,&k);
		for (int i=1;i<=m;i++)
		 for (int j=1;j<=m;j++) ch.a[i][j]=1;
		for (int i=1;i<=k;i++) {
			int x,y; scanf("%d%d",&x,&y);
			ch.a[x][y]=ch.a[y][x]=0;
		}
		//for (int i=1;i<=m;i++,cout<<endl)
		// for (int j=1;j<=m;j++) cout<<ch.a[i][j]<<" ";
		int ans=0;
		for (int i=1;i*i<=n;i++) 
		 if (n%i==0){
			ans+=calc(i)*getphi(n/i)%p; ans%=p;
			//cout<<calc(i)<<" "<<getphi(n/i)<<endl;
			if (i*i!=n) ans+=calc(n/i)*getphi(i)%p;
			//cout<<calc(n/i)<<" "<<getphi(i)<<endl;
			ans%=p;
		}
		ans=ans*quickpow(n,p-2)%p;
		printf("%d\n",ans);
	}
}


POJ 3213 题目是一个关于矩阵乘法的经典计算机科学问题。矩阵乘法通常是线性代数的基础操作,给定两个矩阵 A 和 B,你需要计算它们的乘积 C = A * B,其中每个元素 C[i][j] 是对应位置上 A 的行向量与 B 的列向量的点积。 以下是一个简单的 Java 代码示例,使用嵌套循环来实现矩阵乘法: ```java import java.util.Scanner; public class MatrixMultiplication { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 输入矩阵的维度 System.out.println("Enter the dimensions of matrix A (m x n):"); int m = scanner.nextInt(); int n = scanner.nextInt(); // 创建矩阵 A 和 B int[][] matrixA = new int[m][n]; int[][] matrixB = new int[n][n]; // 读取矩阵 A 的元素 System.out.println("Enter elements of matrix A:"); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { matrixA[i][j] = scanner.nextInt(); } } // 读取矩阵 B 的元素(假设输入的矩阵都是方阵,大小为 n x n) System.out.println("Enter elements of matrix B:"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { matrixB[i][j] = scanner.nextInt(); } } // 矩阵乘法 int[][] result = new int[m][n]; // 结果矩阵 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { // 每次循环k用于遍历B的列 result[i][j] += matrixA[i][k] * matrixB[k][j]; } } } // 输出结果矩阵 System.out.println("Matrix multiplication result:"); for (int[] row : result) { for (int element : row) { System.out.print(element + " "); } System.out.println(); } scanner.close(); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值