POJ 2888 Magic Bracelet(Burnside引理+欧拉函数+矩阵快速幂+逆元)

来源:互联网 发布:华为防火墙开放端口 编辑:程序博客网 时间:2024/06/05 15:31
Magic Bracelet
Time Limit: 2000MS Memory Limit: 131072KTotal Submissions: 5749 Accepted: 1850

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

43 2 03 2 11 23 2 21 11 23 2 31 11 22 2

Sample Output

4210

Source

POJ Monthly--2006.07.30, cuiaoxiang

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

Home Page   Go Back  To top


题意:n个珠子组成项链,m种颜色为其染色,然而有k种关系限制。即颜色x和颜色y不能相邻。

题解:假如没有颜色不相邻限制的话就是polya定理计数模板题了,有了限制的话我们就不能用polya定理了。

呢该怎么办呢?用了半天容斥原理发现根本不对。。看了题解,真的是神题。。。。。

既然polya定理不适用,呢我们就要考虑Burnside引理了(换着用?)

我们首先回顾一下burnside引理:一个本质不同的组合数等于所有置换下不动点的个数之和除以置换种类数。

因为这题只有旋转,并且项链的旋转是有规律的,不难发现,每一个循环节中相邻的珠子的距离是相同的。

可是这和解这道题有关系吗?先别着急,我们往下走,此时我们可以求出同一个循环节中相邻珠子的距离一定为

gcd(i,n),假如我们从任意一个珠子开始顺时针数起,这gcd(n,i)个珠子一定在不同循环节中。还是呢句话,这和这道题有关系吗?   说实话,不看题解我是真的无从下手,题解也是看了将近3个小时。。越看越迷。。。

但其实想到这里问题已经解决了不是吗?根据burnside引理,不就是求长度为gcd(i,n)的珠子的染色数嘛。。

剩下的问题就好办了,对于gcd(i,n),我们可以用欧拉函数降低复杂度,然后对于合法染色数,我们可以考虑用矩阵优化,因为最后要除以n,而n又很大,我们可以让其乘上n的逆元即可。。。

#include<set>      #include<map>         #include<stack>                #include<queue>                #include<vector>        #include<string>     #include<time.h>    #include<math.h>                #include<stdio.h>                #include<iostream>                #include<string.h>                #include<stdlib.h>        #include<algorithm>       #include<functional>        using namespace std;                #define ll long long          #define inf 1000000000         #define mod 9973               #define maxn  50005    #define lowbit(x) (x&-x)                #define eps 1e-9   int a[maxn]={1,1},b[maxn],cnt; struct node{ll x[15][15];}aa;void init(){ll i,j;for(i=2;i<maxn;i++)      {          if(a[i])              continue;          b[++cnt]=i;          for(j=i*i;j>0 && j<maxn;j+=i)              a[j]=1;      }  }ll q(ll x,ll y)    {        ll res=1;        while(y)        {            if(y%2)                res=res*x%mod;            x=x*x%mod;            y/=2;        }        return res;    } node q2(node a,node b,ll m){ll i,j,k;node c;for(i=1;i<=m;i++)for(j=1;j<=m;j++){c.x[i][j]=0;for(k=1;k<=m;k++)c.x[i][j]=c.x[i][j]+a.x[i][k]*b.x[k][j];c.x[i][j]%=mod;}return c;}node q1(node a,ll y,ll m){node b;int i,j;for(i=1;i<=m;i++)for(j=1;j<=m;j++){if(i==j)b.x[i][j]=1;elseb.x[i][j]=0;}while(y){if(y%2)b=q2(b,a,m);a=q2(a,a,m);y/=2;}return b;}ll ol(ll x)    {        ll i,res=x;        for(i=1;i<=cnt && b[i]*b[i]<=x;i++)        {            if(x%b[i]==0)            {                res=res-res/b[i];                while(x%b[i]==0)                    x/=b[i];            }        }        if(x>1)            res=res-res/x;        return res;    }   ll work(node a,ll m){ll ans=0;int i;for(i=1;i<=m;i++)ans=(ans+a.x[i][i])%mod;return ans;}int main(void)    {    int t;init();    ll n,m,i,j,k,x,y;    scanf("%d",&t);    while(t--)        {   scanf("%lld%lld%lld",&n,&m,&k);for(i=1;i<=m;i++)for(j=1;j<=m;j++)aa.x[i][j]=1;for(i=1;i<=k;i++){scanf("%lld%lld",&x,&y);aa.x[x][y]=aa.x[y][x]=0;}ll ans=0;for(i=1;i*i<=n;i++){if(n%i==0){node tmp;tmp=q1(aa,i,m);ans=(ans+ol(n/i)%mod*work(tmp,m)%mod)%mod;if(i*i==n)break;tmp=q1(aa,n/i,m);ans=(ans+ol(i)%mod*work(tmp,m)%mod)%mod;}}ans=(ans*q(n,mod-2))%mod;printf("%lld\n",ans);    }        return 0;    }  



阅读全文
0 0
原创粉丝点击