poj 2888 Magic Bracelet 有限制条件的(有限制条件的polay问题)
我学习组合数学,几乎全部是自学,很多的东西都不知道怎么搞,资料也很难找到合适的,我想这就是弱校的难处,但是我还是会继续努力下去的,其实,我现在觉得笨小孩的博客挺好的,博客地址如下:http://hi.baidu.com/%B1%BF%D0%A1%BA%A2_shw/blog/category/%D1%A7%CF%B0%D0%A1%BD%E1
这个题是说,某两种珠子不能放在一起,组合数学中有几句话是这么说的:
组合计数问题中经常遇到两种困难,第一找出问题通解的表达式,第二是区分讨论问题中哪些应该看成相同的。把这句话放到这儿就是,置换群的知识和polya定理解决了方案的相同的区别问题,可是计数问题怎么解决?假设没有旋转和反转,又怎么解决这个问题?
在《十个利用矩阵乘法解决的经典题目》中有介绍,也就是无向图长度为n的回路的个数,项链不就是一个回路嘛!!
这个题,可以说是用模板堆出来的,大部分的代码都是模板,矩阵乘法,矩阵快速幂,素数筛,欧拉函数,polya,当然,由于这些模板我从来没有放在一起用过,也出现了一点问题,还好,最后改对了ac掉了这个题。
代码如下:
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
int n,m,k;
#define PP 100010
int prime[PP];
bool isPrime[PP+1];
int size;
void getPrime() {
memset(isPrime,true,sizeof(isPrime));
int i;
for(i=2; i<=PP/2; i++) {
if(isPrime[i]) //i是素数
for(int j=i+i; j<=PP; j+=i)
isPrime[j]=0;
}
for(i=2; i<=PP; i++) {
if(isPrime[i])
prime[size++]=i;
}
}
#define N 11 // 标注矩阵的大小
struct Matrix
{
long long matrix[N][N]; //每个元素
long long row,coloumn;
//注意这个地方前后要对应
// Matrix(){
// memset(matrix,0,sizeof(matrix));
// }
}thisM,pw[33];
bool b = 0;
#define M 9973 // 模的大小
Matrix mutiply(Matrix a,Matrix b) //返回a*b
{
long long i,j,k;
Matrix ans;
memset(ans.matrix,0,sizeof(ans.matrix));
ans.row = a.row;
ans.coloumn = b.coloumn;
for(i=0; i<a.row; i++)
for(k=0; k<a.coloumn; k++)
if(a.matrix[i][k]) //优化
for(j=0; j<b.coloumn; j++)
{
ans.matrix[i][j]=(ans.matrix[i][j] + (a.matrix[i][k]*b.matrix[k][j])%M)%M;
}
return ans;
}
//(二进制)矩阵快速幂 //调矩阵乘法
Matrix matrix_mi(Matrix p,int k)// (二进制)矩阵快速幂
{
Matrix t;
t.coloumn = t.row = m;
//init(t); ///注意初始化
memset(t.matrix,0,sizeof(t.matrix));
for(int i=0; i< N; i++) t.matrix[i][i]=1; //t初值为1 初始化;N为数组长度;声明时需初始化,否则其他的值不确定。
int tt = 0;
pw[tt] = p;
while(k)
{
if(b)
{
if(k&1)
t=mutiply(t,pw[tt]);
}else
pw[tt+1] = mutiply(pw[tt],pw[tt]);
k>>=1;
tt++;
}
b = 1;
return t;
}
int Euler(int n)//求欧拉函数
{
//cout << n ;
int i,l,t;
l=n;
for (i=0;i<size;i++)
{
t=0;
while (l%prime[i]==0) { t++; l=l/prime[i]; }
if (t>0) n=n/prime[i]*(prime[i]-1);
if (l==1) break;
if (l/prime[i]<prime[i]) { n=n/l*(l-1); break; }
}
//cout << "euler:" << n << "\n";
return n%M;
}
int geter(int i)
{
int tt = 0;
Matrix ts = matrix_mi(thisM, i);
for(int j =0;j < m;j++)
tt += ts.matrix[j][j];
//cout << i << " " << tt << " " << m << "\n";
return tt%M;
}
long long polya(int c,int n)
{
geter(n);
long long an = 0;
for (int i = 1; i*i <= n; i++) if (n % i == 0) {
an = (an+( geter(i) * Euler(n / i) ) % M)%M;
if(i*i != n) an = (an+( geter(n/i) * Euler(i) ) % M)%M;
}
int i;
for (i=1;;i++) { if (((long long int)(n)*i-an)%M==0) break; }
return i%M;
}
int main()
{
getPrime();
int cas;
//cin >> cas;
scanf("%d",&cas);
while(cas--)
{
b = 0;
//cin >> n >> m >> k;
scanf("%d%d%d",&n,&m,&k);
thisM.coloumn = m;
thisM.row = m;
for(int i = 0;i < m;i++) for(int j = 0;j < m;j++)
thisM.matrix[i][j] = 1;
int a,b;
for(int i = 0;i < k;i++)
{
scanf("%d%d",&a,&b);
//cin >> a >> b;
a--;b--;
thisM.matrix[a][b] = 0;
thisM.matrix[b][a] = 0;
}
printf("%d\n",(int)polya(m,n));
}
return 0;
}