poj 2888 Magic Bracelet 有限制条件的(有限制条件的polay问题)

 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;
}



你可能感兴趣的:(poj 2888 Magic Bracelet 有限制条件的(有限制条件的polay问题))