• 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

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <cmath>
      5 using namespace std;
      6 const int mod = 9973;
      7 const int maxn = 12;
      8 int n, m, k, n1;
      9 int prime[50], k1;
     10 int p2[50], k2;
     11 int cnt[50];
     12 int ans;
     13 
     14 struct Matrix{
     15     int matrix[maxn][maxn];
     16 }B, C;
     17 
     18 Matrix operator * (Matrix A, Matrix B){
     19     Matrix C;
     20     memset(C.matrix, 0, sizeof C.matrix);
     21     for(int i = 0; i < m; i++){
     22         for(int j = 0; j < m; j++){
     23             for(int u = 0; u < m; u++){
     24                 int p = A.matrix[i][u], q = B.matrix[u][j];
     25                 if(p && q) C.matrix[i][j] += p * q;
     26             }
     27             C.matrix[i][j] %= mod;
     28         }
     29     }
     30     return C;
     31 }
     32 
     33 Matrix operator ^ (Matrix A, int p){
     34     Matrix C;
     35     memset(C.matrix, 0, sizeof C.matrix);
     36     for(int i = 0; i < m; i++) C.matrix[i][i] = 1;
     37     while(p){
     38         if(p & 1) C = C * A;
     39         p >>= 1;
     40         A = A * A;
     41     }
     42     return C;
     43 }
     44 
     45 int phi(int num){
     46     k2 = 0;
     47     for(int i = 0; i < k1; i++) if(num % prime[i] == 0) num /= prime[i], p2[k2++] = prime[i];
     48     for(int i = 0; i < k2; i++) num *= p2[i] - 1;
     49     return num % mod;
     50 }
     51 
     52 int power(int a, int p){
     53     a %= mod;
     54     int ans = 1;
     55     while(p){
     56         if(p & 1) ans *= a, ans %= mod;
     57         p >>= 1;
     58         a *= a;
     59         a %= mod;
     60     }
     61     return ans;
     62 }
     63 
     64 void dfs(int pos, int num){
     65     if(pos == k1){
     66         C = B ^ num;
     67         int ans1 = 0;
     68         for(int i = 0; i < m; i++) ans1 += C.matrix[i][i], ans1 %= mod;
     69         ans1 = (ans1 * phi(n / num)) % mod;
     70         ans = (ans + ans1) % mod;
     71         return;
     72     }
     73     int tem = num;
     74     for(int i = 0; i <= cnt[pos]; i++){
     75         dfs(pos + 1, tem);
     76         tem *= prime[pos];
     77     }
     78 }
     79 
     80 void solve(){
     81     n1 = n;
     82     k1 = 0;
     83     memset(cnt, 0, sizeof cnt);
     84     if(!(n & 1)){
     85         prime[k1++] = 2;
     86         while(!(n & 1)) n >>= 1, ++cnt[k1 - 1];
     87     }
     88     int mid = (int)sqrt(n);
     89     for(int i = 3; i <= mid; i += 2){
     90         if(n % i == 0){
     91             prime[k1++] = i;
     92             while(n % i == 0) n /= i, ++cnt[k1 - 1];
     93             mid = (int)sqrt(n);
     94         }
     95     }
     96     if(n != 1) prime[k1++] = n, ++cnt[k1 - 1];
     97     n = n1;
     98     ans = 0;
     99     dfs(0, 1);
    100     ans = ans * power(n, mod - 2) % mod;
    101     printf("%d
    ", ans);
    102 }
    103 
    104 int main(){
    105     //freopen("in.txt", "r", stdin);
    106     int T;
    107     scanf("%d", &T);
    108     while(T--){
    109         scanf("%d%d%d", &n, &m, &k);
    110         for(int i = 0; i < m; i++) for(int j = 0; j < m; j++) B.matrix[i][j] = 1;
    111         for(int i = 0, p, q; i < k; i++){
    112             scanf("%d%d", &p, &q);
    113             --p, --q;
    114             B.matrix[p][q] = B.matrix[q][p] = 0;
    115         }
    116         solve();
    117     }
    118     return 0;
    119 }
    View Code
  • 相关阅读:
    第十四周课程总结&实验报告(简单记事本的实现)
    第十三周课程总结
    第十二周课程总结
    第十一周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
    第八周课程总结&实验报告(六)
    第七周课程总结&试验报告(五)
    基于C的
    RMQ 区间最值问题
  • 原文地址:https://www.cnblogs.com/astoninfer/p/4823140.html
Copyright © 2020-2023  润新知