思路挺清晰的。不过,我就是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;
}

  

POJ 2888的更多相关文章

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

    Magic Bracelet Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 4990   Accepted: 1610 D ...

  2. poj 2888 Magic Bracelet <polya定理>

    题目:http://poj.org/problem?id=2888 题意:给定n(n <= 10^9)颗珠子,组成一串项链,每颗珠子可以用m种颜色中一种来涂色,如果两种涂色方法通过旋转项链可以得 ...

  3. POJ 2888 Magic Bracelet(Burnside引理,矩阵优化)

    Magic Bracelet Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 3731   Accepted: 1227 D ...

  4. poj 2888 Magic Bracelet

    经典的有限制条件的Burnside计数+矩阵乘法!!! 对于这种限制条件的情况我们可以通过矩阵连乘得到,先初始化矩阵array[i][j]为1.如果颜色a和颜色b不能涂在相邻的珠子, 那么array[ ...

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

    题意:一个长度为n的项链,m种颜色染色每个珠子.一些限制给出有些颜色珠子不能相邻.旋转后相同视为相同.有多少种不同的项链? 思路:这题有点综合,首先,我们对于每个n的因数i,都考虑这个因数i下的不变置 ...

  6. POJ 2888 Magic Bracelet [Polya 矩阵乘法]

    传送门 题意:竟然扯到哈利波特了.... 和上一题差不多,但颜色数很少,给出不能相邻的颜色对 可以相邻的连边建图矩阵乘法求回路个数就得到$f(i)$了.... 感觉这样的环上有限制问题挺套路的...旋 ...

  7. 解题:POJ 2888 Magic Bracelet

    题面 这题虽然很老了但是挺好的 仍然套Burnside引理(因为有限制你并不能套Polya定理),思路和这个题一样,问题主要是如何求方案. 思路是把放珠子的方案看成一张图,然后就巧妙的变成了一个经典的 ...

  8. POJ 2888 Magic Bracelet ——Burnside引理

    [题目分析] 同样是Burnside引理.但是有几种颜色是不能放在一起的. 所以DP就好了. 然后T掉 所以矩阵乘法就好了. 然后T掉 所以取模取的少一些,矩阵乘法里的取模尤其要注意,就可以了. A掉 ...

  9. [POJ 2888]Magic Bracelet[Polya Burnside 置换 矩阵]

    也许更好的阅读体验 \(\mathcal{Description}\) 大意:给一条长度为\(n\)的项链,有\(m\)种颜色,另有\(k\)条限制,每条限制为不允许\(x,y\)颜色连在一起.要求有 ...

随机推荐

  1. [Azure][Windows Azure介绍]C1了解Windows Azure

    本章介绍了Windows Azure平台,并介绍了该平台提供的不同的服务和解决方案.本章主要针对还不熟悉什么Windows Azure是和它能做什么的读者.如果你已经熟悉了Windows Azure, ...

  2. Android设计模式(三)--装饰模式

    1.定义: Attach additional responsibilities to an object dynamically keeping the same interface.  Decoa ...

  3. 微软ASP.NET网站部署指南(3):使用Web.Config文件的Transformations

    1. 综述 大多数程序里都会在Web.config里设置參数,而且在部署的时候须要更改. 每次都手工更改这些配置非常乏味,也easy出错. 该章节将会告诉你假设通过自己主动化更新Web.config文 ...

  4. Spring经常使用属性的注入及属性编辑器

    对于对象的注入,我们使用ref方式,能够指定注入的对象.以下看下对于基本类型的注入.以及当spring无法转换基本类型进行注入时,怎样编写一个相似转换器的东西来完毕注入. 一.基本类型的注入 以下写一 ...

  5. 编写函数int count_number_string(char str[])和函数int maxnum_string(char str[])

    题目如图: 这里不再赘述 代码: //字符串中统计与查询 //杨鑫 #include <stdio.h> #include <stdlib.h> #include <st ...

  6. 0x27 A*

    终于完全了解A*到底是什么玩意儿了 对于当前的决策,选取当前花费+预估花费最小来拓展. 因为假如预估出现失误,那么很可能就会延伸到一个错误的决策点,而这个决策点偏偏就是ed,而由于预估失误,其他点的当 ...

  7. c语言循环案例

    do while #include <stdio.h> #include <stdlib.h> int main() { int a = 1,b = 10; do { b -= ...

  8. mysqli的简单工具包

    mysqli的简单工具包 <?php /** * 连接 * @param string $host * @param string $user * @param string $password ...

  9. 【POJ 2482】 Stars in Your Windows

    [题目链接] http://poj.org/problem?id=2482 [算法] 线段树 + 扫描线 [代码] #include <algorithm> #include <bi ...

  10. dubbo 解决既是消费者又是提供者 Duplicate application configs 的问题

    首先  有应用A  是 提供者 应用B 来实现既是消费者又是提供者 在应用 B 这边新建两个xml dubbo-consumer.xml  消费者 <!-- 自动扫描注解:通过dubbo实现 - ...