POJ 2888 Magic Bracelet

来源:互联网 发布:java反射的应用 编辑:程序博客网 时间:2024/06/08 04:11

Burnside引理+欧拉函数+矩阵乘法。

突然发现Burnside引理忘得差不多了(根本没学会好吗)

今天才知道不动点原来是这么求的,以前都是循环k=1->n,ans+=calc(gcd(n,k))

现在反过来,令gcd(n,k)=r,ans+=calc(r)*euler(n/r),显然gcd(n/r,k/r)=1,所以循环节为r的循环一共有euler(n/r)个。

然后还有就是计数其实相当于在有m个顶点的图上走,所以设邻接矩阵g[i][j]表示从i走到j有g[i][j]种走法(本题显然就一种),然后g^k就可以求出从i走k步到j有几种走法,矩阵快速幂一下就好了。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int p=9973;const int N=10+2;int qmul(int a,int b){int ans=1;a%=p;for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;return ans;}int inv(int x){return qmul(x,p-2);}int phi(int x){int ans=x;for(int i=2;i*i<=x;i++)if(x%i==0){while(x%i==0)x/=i;ans=ans/i*(i-1);}if(x>1)ans=ans/x*(x-1);return ans%p;}int m;struct Matrix{int a[N][N];Matrix(){memset(a,0,sizeof(a));}};Matrix operator * (Matrix a,Matrix b){Matrix c;for(int i=1;i<=m;i++)for(int k=1;k<=m;k++)if(a.a[i][k])for(int j=1;j<=m;j++)if(b.a[k][j])c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%p;return c;}Matrix operator ^ (Matrix a,int k){Matrix ans;for(int i=1;i<=m;i++)ans.a[i][i]=1;for(;k;k>>=1,a=a*a)if(k&1)ans=ans*a;return ans;}Matrix A,B;int calc(int x){B=A^x;int ans=0;for(int i=1;i<=m;i++)ans=(ans+B.a[i][i])%p;return ans;}int solve(int n){int ans=0;for(int i=1;i*i<=n;i++)if(n%i==0){ans=(ans+phi(i)*calc(n/i)%p)%p;if(n/i!=i)ans=(ans+phi(n/i)*calc(i)%p)%p;}ans=ans*inv(n)%p;return ans;}int main(){//freopen("a.in","r",stdin);int T;scanf("%d",&T);while(T--){int n,k;scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)A.a[i][j]=1;while(k--){int u,v;scanf("%d%d",&u,&v);A.a[u][v]=A.a[v][u]=0;}printf("%d\n",solve(n));}return 0;}


0 0
原创粉丝点击