poj2888 Magic Bracelet
给你一个正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的更多相关文章
- POJ-2888 Magic Bracelet(Burnside引理+矩阵优化+欧拉函数+逆元)
Burnside引理经典好题呀! 题解参考 https://blog.csdn.net/maxwei_wzj/article/details/73024349#commentBox 这位大佬的. 这题 ...
- 【POJ2888】Magic Bracelet Burnside引理+欧拉函数+矩阵乘法
[POJ2888]Magic Bracelet 题意:一个长度为n的项链,有m种颜色的珠子,有k个限制(a,b)表示颜色为a的珠子和颜色为b的珠子不能相邻,求用m种珠子能串成的项链有多少种.如果一个项 ...
- POJ 2888 Magic Bracelet(Burnside引理,矩阵优化)
Magic Bracelet Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 3731 Accepted: 1227 D ...
- poj 2888 Magic Bracelet(Polya+矩阵快速幂)
Magic Bracelet Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 4990 Accepted: 1610 D ...
- poj 2888 Magic Bracelet
经典的有限制条件的Burnside计数+矩阵乘法!!! 对于这种限制条件的情况我们可以通过矩阵连乘得到,先初始化矩阵array[i][j]为1.如果颜色a和颜色b不能涂在相邻的珠子, 那么array[ ...
- POJ 2888 Magic Bracelet(burnside引理+矩阵)
题意:一个长度为n的项链,m种颜色染色每个珠子.一些限制给出有些颜色珠子不能相邻.旋转后相同视为相同.有多少种不同的项链? 思路:这题有点综合,首先,我们对于每个n的因数i,都考虑这个因数i下的不变置 ...
- POJ 2888 Magic Bracelet [Polya 矩阵乘法]
传送门 题意:竟然扯到哈利波特了.... 和上一题差不多,但颜色数很少,给出不能相邻的颜色对 可以相邻的连边建图矩阵乘法求回路个数就得到$f(i)$了.... 感觉这样的环上有限制问题挺套路的...旋 ...
- 解题:POJ 2888 Magic Bracelet
题面 这题虽然很老了但是挺好的 仍然套Burnside引理(因为有限制你并不能套Polya定理),思路和这个题一样,问题主要是如何求方案. 思路是把放珠子的方案看成一张图,然后就巧妙的变成了一个经典的 ...
- poj 2888 Magic Bracelet <polya定理>
题目:http://poj.org/problem?id=2888 题意:给定n(n <= 10^9)颗珠子,组成一串项链,每颗珠子可以用m种颜色中一种来涂色,如果两种涂色方法通过旋转项链可以得 ...
随机推荐
- 【转】Tomcat组件生命周期管理
Tomcat组件生命周期管理 Tomcat中Server,Service,Connector,Engine,Host,Context,它们都实现了org.apache.catalina.Lifecyc ...
- InterProScan 5.17-56.0 安装和使用
InterProScan 5.18-57.0 安装和使用,目前最新版的interproscan 引用自 每日一生信--interproscan安装及使用(终结版)原文官网:http://code.go ...
- devexpress13学习系列(一)PDFViewer(1)
使用这个组件,可以直接在winform里显示pdf文档,不需要另外装软件了. 有这么几个重要的属性: 1.DocumentFilePath:要读取的PDF的文件和路径. 2.CurrentPageNu ...
- eclipse lua使用
首先安装lua eclipse,装插件或者独立版的都可以.但是在独立版的eclipse装subclipse会报错,Failed to prepare partial IU.解决办法: work aro ...
- G面经prepare: BuyGoods
给你一部分钱和一些不同价钱的商品,如何在最多买K件商品的情况下尽可能多的花掉手里的钱. 举例:口袋里的钱数: 10; K=2 产品价格: [3, 6, 8, 7, 9] 输出 3, 7 Backtra ...
- 求树的重心(POJ1655)
题意:给出一颗n(n<=2000)个结点的树,删除其中的一个结点,会形成一棵树,或者多棵树,定义删除任意一个结点的平衡度为最大的那棵树的结点个数,问删除哪个结点后,可以让平衡度最小,即求树的重心 ...
- java mybatis 框架下多种类型的参数传入到xml问题
由于公司要求,最近从.net向java 转,然后过程中遇到各种奇葩问题,特在此随记一番. 场景:一个方法中有两个参数,一个List的集合,一个int 类型的参数,最初我在xml的sql参数,无论定义成 ...
- C# 多线程 lock 实例
class Program { static void Main(string[] args) { //在t1线程中调用LockMe,并将deadlock设为true(将出现死锁) int i = 1 ...
- sql 中延迟执行
SQL有定时执行的语句WaitFor. 语法格式:waitfor {delay 'time'|time 'time'} delay后面的时间是需要延迟多长时间后执行. time后面的时间是指定何时执行 ...
- 夺命雷公狗---微信开发13----获取access_token
获得Access Token的方法1: 这里可以手动进行修改: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential ...