给你一个正n(<10^9)边形和m(<10)种色料,要求给正n边形顶点染色并且规定k组颜色对不能相邻,

输入保证n与mod互质,计数染色总方案数(绕图形中心旋转后相同的方案算一种)对mod取模。

问题的关键在于保证给定的颜色对不相邻,而如果我们用传统的容斥来排除不合法的染色方案在题目给定的n的规模下是不具有可操作性的。

考虑n边形的σi旋转置换,显然有循环:

0 : 0 -> i % n -> 2 *i % n ->... -> 0

1 : 1 -> (i + 1) % n -> (i * 2 + 1) % n ->... -> 1

...

d - 1 : d - 1 -> (i + d - 1) % n -> (i * 2 + d - 1) % n ->... d - 1

即存在d个循环,考虑到每个点的位置是等价的且恰处于一个循环节中,有

各循环节长度相等,其值为l = n / d。

第j + 1个循环中的点p满足 p Ξ j (mod n), 因此若(j + d1 * i ) % n = j,

有d1 * i Ξ 0 (mod n), d1 的最小值为lcm(i, n) / i = n * gcd(i, n)即循环节长度l。

解出d = gcd(i, n)。

显然每个循环节内染色相同,假设第i个循环节染色c(i)。

则n边形染色:c(0) -> c(1) ->...-> c(d - 1) -> c(0) -> c(1) ->....c(d - 1)。

这等价于我们用m种颜色对d 边形染色,同时保证染色合法。

也就是说保证染色:(c(0)c(1)) (c(1)c(2))...(c(d-1)c(0))中成对颜色是合法的。(*)

即便到此用容斥解决也是不可行的,需要将其实现到可快速计算的载体中。

令f(p, q)=

1,若p, q色料可以相邻。

0,其他。

则(*)等价于f(c(0), c(1)) * ... * f(c(d-1), c(0)) = 1。

也就是说每种可行方案为该连乘式贡献1。

考虑布尔矩阵F:

F^n(i,j)表示从i到j路径长度为n的路径总数(这里假设任两点之间距离为1)。

如此所求方案数即∑φ(n / d) * F^d * Inversion(n, mod) % mod (d | n)。

http://poj.org/problem?id=2888

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int mod = ;
const int maxn = ;
int n, m, k, n1;
int prime[], k1;
int p2[], k2;
int cnt[];
int ans; struct Matrix{
int matrix[maxn][maxn];
}B, C; Matrix operator * (Matrix A, Matrix B){
Matrix C;
memset(C.matrix, , sizeof C.matrix);
for(int i = ; i < m; i++){
for(int j = ; j < m; j++){
for(int u = ; u < m; u++){
int p = A.matrix[i][u], q = B.matrix[u][j];
if(p && q) C.matrix[i][j] += p * q;
}
C.matrix[i][j] %= mod;
}
}
return C;
} Matrix operator ^ (Matrix A, int p){
Matrix C;
memset(C.matrix, , sizeof C.matrix);
for(int i = ; i < m; i++) C.matrix[i][i] = ;
while(p){
if(p & ) C = C * A;
p >>= ;
A = A * A;
}
return C;
} int phi(int num){
k2 = ;
for(int i = ; i < k1; i++) if(num % prime[i] == ) num /= prime[i], p2[k2++] = prime[i];
for(int i = ; i < k2; i++) num *= p2[i] - ;
return num % mod;
} int power(int a, int p){
a %= mod;
int ans = ;
while(p){
if(p & ) ans *= a, ans %= mod;
p >>= ;
a *= a;
a %= mod;
}
return ans;
} void dfs(int pos, int num){
if(pos == k1){
C = B ^ num;
int ans1 = ;
for(int i = ; i < m; i++) ans1 += C.matrix[i][i], ans1 %= mod;
ans1 = (ans1 * phi(n / num)) % mod;
ans = (ans + ans1) % mod;
return;
}
int tem = num;
for(int i = ; i <= cnt[pos]; i++){
dfs(pos + , tem);
tem *= prime[pos];
}
} void solve(){
n1 = n;
k1 = ;
memset(cnt, , sizeof cnt);
if(!(n & )){
prime[k1++] = ;
while(!(n & )) n >>= , ++cnt[k1 - ];
}
int mid = (int)sqrt(n);
for(int i = ; i <= mid; i += ){
if(n % i == ){
prime[k1++] = i;
while(n % i == ) n /= i, ++cnt[k1 - ];
mid = (int)sqrt(n);
}
}
if(n != ) prime[k1++] = n, ++cnt[k1 - ];
n = n1;
ans = ;
dfs(, );
ans = ans * power(n, mod - ) % mod;
printf("%d\n", ans);
} int main(){
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d%d", &n, &m, &k);
for(int i = ; i < m; i++) for(int j = ; j < m; j++) B.matrix[i][j] = ;
for(int i = , p, q; i < k; i++){
scanf("%d%d", &p, &q);
--p, --q;
B.matrix[p][q] = B.matrix[q][p] = ;
}
solve();
}
return ;
}

poj2888 Magic Bracelet的更多相关文章

  1. POJ-2888 Magic Bracelet(Burnside引理+矩阵优化+欧拉函数+逆元)

    Burnside引理经典好题呀! 题解参考 https://blog.csdn.net/maxwei_wzj/article/details/73024349#commentBox 这位大佬的. 这题 ...

  2. 【POJ2888】Magic Bracelet Burnside引理+欧拉函数+矩阵乘法

    [POJ2888]Magic Bracelet 题意:一个长度为n的项链,有m种颜色的珠子,有k个限制(a,b)表示颜色为a的珠子和颜色为b的珠子不能相邻,求用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(Polya+矩阵快速幂)

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

  5. poj 2888 Magic Bracelet

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

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

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

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

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

  8. 解题:POJ 2888 Magic Bracelet

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

  9. poj 2888 Magic Bracelet <polya定理>

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

随机推荐

  1. views of postgresql user password and encrypted or unencrypted

    password_encryption = onpostgres=# create user user1 with encrypted password 'user1';CREATE ROLEpost ...

  2. SQL 数据库 right join 和left join 的区别

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...

  3. 初始化 Gradle 工程目录(转自: 隔叶黄莺 Unmi Blog)

    最近重新在 Eclipse 中打开旧的 Maven 项目,总有些什么错误,备受折磨.期间试手了 Ant+Ivy, 现今试用了下 Gradle,感觉不错,它应该才是我真想要的,Maven 差不多该扔到一 ...

  4. FAQ: C++中定义类的对象:用new和不用new有何区别?

    C++用new创建对象和不用new创建对象的区别解析 作者: 字体:[增加 减小] 类型:转载 时间:2013-07-26 我要评论 在C++用new创建对象和不用new创建对象是有区别的,不知你是否 ...

  5. Linux 系统结构

    Linux的系统结构一般由四部分组成 内核 1)内核 操作系统的核心,具有最基本的功能:内存管理.进程管理.设备驱动管理.文件系统管理,网络管理 内核版本(kernel)查看的三种方法 cat /pr ...

  6. ofbiz进击 第一节。 新建自己的webapp项目

    创建一个webapp的过程更新下来项目(直接从svn上面切下来就好),要先ant clean 下,然后在重新ant下.一: start sheel here :ant create-component ...

  7. HDFS简介

    Hadoop是当今最为流行的大数据分析和处理工具. 其最先的思想来源于Google的三篇论文:                            GFS(Google File System):是 ...

  8. paper 42 :图像的小波变换

    关于小波变换我只是有一个很朴素了理解.不过小波变换可以和傅里叶变换结合起来理解. 傅里叶变换是用一系列不同频率的正余弦函数去分解原函数,变换后得到是原函数在正余弦不同频率下的系数. 小波变换使用一系列 ...

  9. mybatis的xml中特殊转义字符和模糊查询like的写法

    做个备忘: xml特殊符号转义写法 <          < >          > <>   <> &      & &ap ...

  10. MyEclipse 死掉,JVM terminated. Exit code=1073807364

    刚入手的新成员,刚开始使用myeclipse,是不是会有一大堆的问题,然后没有目标的走,这里有个小技巧,那就是如果做项目出现问题,一定要自己现在网络搜寻答案,网络时代.技术时代走到现在,一定有他的道理 ...