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

  

时间: 2024-10-14 11:01:06

POJ 2888的相关文章

poj 2888 Magic Bracelet(Polya+矩阵快速幂)

Magic Bracelet Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 4990   Accepted: 1610 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

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

题意:一个长度为n的项链,m种颜色染色每个珠子.一些限制给出有些颜色珠子不能相邻.旋转后相同视为相同.有多少种不同的项链? 思路:这题有点综合,首先,我们对于每个n的因数i,都考虑这个因数i下的不变置换个数,然后乘以(n/i)的欧拉函数加到ans上面,然后再让ans乘以n在模p下的逆元.至于怎么求因数i下的不变置换个数,相信大家都做过没有限制的,至于有限制的,大家可以考虑一下这样:初始数组a[m][m]都为1,对于每个限制x,y,都令a[x][y]=a[y][x]=0,我们有一个数列:b1,b2

poj 2409+2154+2888(Burnside定理)

三道burnside入门题: Burnside定理主要理解置换群置换后每种不动点的个数,然后n种不动点的染色数总和/n为answer. 对于旋转,旋转i个时不动点为gcd(n,i). 传送门:poj 2409 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #include <cstdlib> #de

POJ题目分类推荐 (很好很有层次感)

著名题单,最初来源不详.直接来源:http://blog.csdn.net/a1dark/article/details/11714009 OJ上的一些水题(可用来练手和增加自信) (POJ 3299,POJ 2159,POJ 2739,POJ 1083,POJ 2262,POJ 1503,POJ 3006,POJ 2255,POJ 3094) 初期: 一.基本算法: 枚举. (POJ 1753,POJ 2965) 贪心(POJ 1328,POJ 2109,POJ 2586) 递归和分治法. 递

POJ 刷题指南

OJ上的一些水题(可用来练手和增加自信) (POJ 3299,POJ 2159,POJ 2739,POJ 1083,POJ 2262,POJ 1503,POJ 3006,POJ 2255,POJ 3094) 初期: 一.基本算法: 枚举. (POJ 1753,POJ 2965) 贪心(POJ 1328,POJ 2109,POJ 2586) 递归和分治法. 递推. 构造法.(POJ 3295) 模拟法.(POJ 1068,POJ 2632,POJ 1573,POJ 2993,POJ 2996) 二

图论 500题——主要为hdu/poj/zoj

转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并查集======================================[HDU]1213   How Many Tables   基础并查集★1272   小希的迷宫   基础并查集★1325&&poj1308  Is It A Tree?   基础并查集★1856   More i

[ACM] POJ 1442 Black Box (堆,优先队列)

Black Box Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7099   Accepted: 2888 Description Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empt

poj 1952 BUY LOW, BUY LOWER (最长递减子序列+不同子序列计数)

BUY LOW, BUY LOWER Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 8327   Accepted: 2888 Description The advice to "buy low" is half the formula to success in the bovine stock market.To be considered a great investor you must also f

poj题库分类

初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法:     (1)图的深度优先遍历和广度优先遍历.     (2)最短路径算法(dijkstra,bellman-ford,floyd,hea