POJ 2888 Magic Bracelet(burnside引理+矩阵)

题目链接:http://poj.org/problem?id=2888

题意:一个长度为n的项链,m种颜色染色每个珠子。一些限制给出有些颜色珠子不能相邻。旋转后相同视为相同。有多少种不同的项链?

思路:旋转k个珠子,有Gcd(n,k)个长度为n/Gcd(n,k)的循环节。对于从某个珠子开始的Gcd(n,k)个珠子不在同一个循环节中。那么对于旋转k,问题转化为有多少长度为p=Gcd(n,k)的合法序列a1,a2,……,ap,使得(a1,a2)(a2,a3)……(ap,a1)均是合法的。求合法矩阵的p次方对角线元素之和即是答案。

 

int n,m,K;



struct Matrix

{

    i64 a[N][N];



    void init(int x)

    {

        clr(a,0);

        if(x)

        {

            int i;

            FOR1(i,m) a[i][i]=1;

        }

    }





    Matrix operator*(Matrix p)

    {

        Matrix ans;

        ans.init(0);

        int i,j,k;

        FOR1(i,m) FOR1(j,m)

        {

            FOR1(k,m) ans.a[i][j]+=a[i][k]*p.a[k][j];

            ans.a[i][j]%=mod;

        }

        return ans;

    }



    Matrix pow(i64 n)

    {

        Matrix ans,p=*this;

        ans.init(1);

        while(n)

        {

            if(n&1) ans=ans*p;

            p=p*p;

            n>>=1;

        }

        return ans;

    }

};





Matrix a;



int cal(int t)

{

    Matrix p=a.pow(t);

    int ans=0,i;

    FOR1(i,m) (ans+=p.a[i][i])%=mod;

    return ans;

}





int main()

{

    rush()

    {

        RD(n,m,K);

        a.init(0);

        int i,j;

        FOR1(i,m) FOR1(j,m) a.a[i][j]=1;

        FOR1(i,K)

        {

            int u,v;

            RD(u,v);

            a.a[u][v]=a.a[v][u]=0;

        }

        int ans=0;

        for(i=1;i*i<=n;i++) if(n%i==0)

        {

            ans+=cal(i)*eular(n/i)%mod;

            if(i*i!=n) ans+=cal(n/i)*eular(i)%mod;

            ans%=mod;

        }

        ans=ans*gcdReverse(n%mod,mod)%mod;

        PR(ans);

    }

}

  

你可能感兴趣的:(ide)