我学习组合数学,几乎全部是自学,很多的东西都不知道怎么搞,资料也很难找到合适的,我想这就是弱校的难处,但是我还是会继续努力下去的,其实,我现在觉得笨小孩的博客挺好的,博客地址如下: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; }