POJ 2888

思路挺清晰的。不过,我就是WA。不清楚为什么,很多数据都过了。

 

其实,一个置换后若有循环节个数为K,则N必定可以除以尽K。而K正好可以看成一个环。为什么呢?看前K个珠子,就是一个环,而后面的若干个K个珠子,不过就是不停的重复而已。这样,循环节的个数可以由最大公约数求得。那么,这个K个珠子构成的环符合题意的有多少种呢?很巧妙的一个方法是,用矩阵表示,若颜色相邻则I,J可以为1,否则为0。矩阵相乘有一个应用就是求的路径数啊。

 

最后,求逆元即可。可我的就是不过,求大神路过时指点。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define MOD 9973
using namespace std;

struct Matrix{
	int m[12][12];
}mat[50];
int m;
bool isprime[35000];
int prime[35000],np;
int dive[100],dn;

Matrix operator * (Matrix a,Matrix b){
	Matrix ret;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=m;j++){
			ret.m[i][j]=0;
			for(int k=1;k<=m;k++){
				ret.m[i][j]=(ret.m[i][j]+(a.m[i][k]*b.m[k][j])%MOD)%MOD;
			}
		}
	}
	return ret;
}
void getprime(){
	memset(isprime,true,sizeof(isprime));
	np=0;
	for(int i=2;i<35000;i++){
		if(isprime[i]){
			prime[np++]=i;
			for(int j=i*i;j<35000;j+=i){
				isprime[j]=false;
			}
		}
	}
}

void divn(int n){
	dn=0;
	int L =(int)sqrt(n*1.0);
	for(int i=1;i<=L;i++){
		if(n%i==0){
			dive[dn++]=i;
			if(i!=n/i)
			dive[dn++]=n/i;
		}
	}
}

void getinit(){
	for(int i=1;i<50;i++){
		mat[i]=mat[i-1]*mat[i-1];
	}
}

int phi(int p){
	int n=p;
	int res=p;
	for(int i=0;i<np&&prime[i]*prime[i]<=n;i++){
		if(p%prime[i]==0){
			res=res-res/prime[i];
			while(p%prime[i]==0)
			p/=prime[i];
		}
	}
	if(p>1)
	res=res-res/p;
	return res%MOD;
}

int quick(int b){
	 Matrix ans;
	 memset(ans.m,0,sizeof(ans.m));
	 for(int i=1;i<=m;i++)
	 ans.m[i][i]=1;
	 int k=0;
	 while(b){
	 	if(b&1) ans=ans*mat[k];
	 	b>>=1;
	 	k++;
	 }
	 int res=0;
	 for(int i=1;i<=m;i++)
	 res=(res+ans.m[i][i])%MOD;
	 return res;
}

void exgcd(int a,int b,int &x,int &y){
	if(b==0){
       x=1;
       y=0;
       return ;
    }
	exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
}

void slove(int n,int m){
	int x,y;
	exgcd(n,MOD,x,y);
	int ans=0;
	for(int i=0;i<dn;i++){
		ans=(ans+(phi(n/dive[i])%MOD)*quick(dive[i]))%MOD;
	}
	x=(x%MOD+MOD)%MOD;
	ans=(ans*x)%MOD;
	printf("%d\n",ans);
}

int main(){
	int n,k,p,q,T;
	getprime();
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=m;i++){
			for(int j=1;j<=m;j++)
			mat[0].m[i][j]=1;
		}
		for(int i=1;i<=k;i++){
			scanf("%d%d",&p,&q);
			mat[0].m[p][q]=mat[0].m[q][p]=0;
		}
		getinit();
		divn(n);
		slove(n,m);
	}
	return 0;
}

  以下是别人的代码:http://blog.csdn.net/tmeteorj/article/details/8654330

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int mr=100000;
const LL mod=9973;
bool notp[mr];
int pr[mr],fac[102],num[102];
int pn,top,n,m;
LL ans;
struct MAT
{
    LL bas[13][13];
    void init()
    {
        memset(bas,0,sizeof(bas));
    }
} mat[50];
MAT mul(MAT a,MAT b)
{
    MAT c;
    c.init();
    for(int i=1; i<=m; i++)
        for(int k=1; k<=m; k++)
        {
            if(a.bas[i][k])
            {
                for(int j=1; j<=m; j++)
                {
                    c.bas[i][j]+=a.bas[i][k]*b.bas[k][j];
                    if(c.bas[i][j]>=mod)
                        c.bas[i][j]%=mod;
                }
            }
        }
    return c;
}
void getpri()//筛素数
{
    pn=0;
    memset(notp,0,sizeof(notp));
    for(int i=2; i<mr; i++)
    {
        if(!notp[i])
        {
            pr[pn++]=i;
        }
        for(int j=0; j<pn && i*pr[j]<mr; j++)
        {
            int k=i*pr[j];
            notp[k]=1;
            if(i%pr[j]==0)break;
        }
    }
}
void divn()
{
    int nn=n;
    top=0;
    int lim=(int)sqrt((double(nn)))+1;
    for(int i=0; pr[i]<=lim; i++)
    {
        if(nn%pr[i]==0)
        {
            fac[top]=pr[i];
            num[top]=0;
            while(nn%pr[i]==0)
                num[top]++,nn/=pr[i];
            top++;
        }
    }
    if(nn>1)
        fac[top]=nn,num[top++]=1;
}
int phi(int x)
{
    int i, res=x;
    for (i=0;pr[i]<(int)sqrt((double)x)+1;i++)
    if(x%pr[i]==0)
    {
        res=res/pr[i]*(pr[i]-1);
        while(x%pr[i]==0)x/=pr[i];
    }
    if(x>1)res=res/x*(x-1);
    return res;
}
void solve(int r)
{
    int res=phi(n/r);
    MAT mt;
    mt.init();
    for(int i=1;i<=m;i++)
        mt.bas[i][i]=1;
    for(int i=1,tp=r;tp;i++,tp>>=1)
    if(tp&1)mt=mul(mt,mat[i]);
    for(int i=1;i<=m;i++)
    {
        ans+=mt.bas[i][i]*res;
        if(ans>=mod)ans%=mod;
    }
}
void dfs(int id,int sum)
{
    if(id==top)
    {
        solve(sum);
        return;
    }
    else
    {
        dfs(id+1,sum);
        for(int ct=0; ct<num[id]; ct++)
            dfs(id+1,sum=sum*fac[id]);
    }
}
void init()
{
    for(int i=2; i<50; i++)
        mat[i]=mul(mat[i-1],mat[i-1]);
}
int Egcd (int a,int b, int &x, int &y)
{
    if (b==0)
    {
        x=1,y=0;
        return a;
    }
    LL d, tp;
    d = Egcd (b, a%b, x, y);
    tp = x;
    x = y;
    y = tp - a/b*y;
    return d;
}
int getni()
{
    int x,y;
    Egcd(n,mod,x,y);
    return (x%mod+mod)%mod;
}
int main()
{
    getpri();
    int T;
    for(scanf("%d",&T); T; T--)
    {
        int k;
        scanf("%d%d%d",&n,&m,&k);
        ans=0;
        for(int i=1; i<=m; i++)
            for(int j=1; j<=m; j++)
                mat[1].bas[i][j]=1;
        for(int a,b,i=0; i<k; i++)
        {
            scanf("%d%d",&a,&b);
            mat[1].bas[a][b]=mat[1].bas[b][a]=0;
        }
        init();
        divn();
        dfs(0,1);
        printf("%d\n",ans*getni()%mod);
    }
    return 0;
}

  

posted @ 2014-10-19 10:51  chenjunjie1994  阅读(313)  评论(0编辑  收藏  举报