sgu208:Toral Tickets(Pólya定理)

题意简述:给你N和M,对于一个N?M的单面方格纸你可以对它的每

个个格子黑白染色,然后把方格纸的长边卷起来,卷成一个圆柱体,然后再把

两个短边形成的圆也接起来,形成一个游泳圈的形状(我们染的色只在游泳圈

的外表面)。如果对于两种黑白染色方案,通过卷成这样的游泳圈后,是一样

的,则这两种方案也是一样的。给定N,M<=20,求染色方案总数.

分析:

首先我们得会Pólya定理,参见http://wenku.baidu.com/view/bf92a95f804d2b160b4ec0be.html

根据题目的要求,分两种情况:

①若N=M,那么就有翻转0o,90o,180o,270o与上下移动,左右移动共N?M?2?2种置换;

②若N≠M,那么就有翻转0o,180o与上下移动,左右移动共N?M?2种置换;

根据Pólya定理,我们分三步:

①暴力搜出所有置换;

②搜出所有置换的循环;

③把答案累加后除以置换数。

时间复杂度:

①O(N?M)②O(N?M)

因此总的为O((N?M)2)

ps.我们需要写高精度,可以预处理2的幂来进行加速。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 29;
const int MAXM = 29;
const int MAXL = 200;

int n, m;

int G;
bool check_square;
int ex[MAXN*MAXM];

struct bigNum
{
    int a[MAXL];
    bigNum(){memset(a, 0, sizeof(a));a[0] = 1;}
    inline void operator += (const bigNum &add)
    {
        a[0] = max(a[0], add.a[0]);
        for(int i = 1; i <= a[0]; ++i)
        {
            a[i] += add.a[i];
            a[i+1] += a[i]/10;
            a[i] %= 10;
        }
        if(a[a[0]+1]) a[0]++;
    }
    inline void operator /= (int k)
    {
        for(int i = a[0]; i > 0; --i)
        {
            a[i-1] += a[i]%k*10;
            a[i] /= k;
        }
        for(; a[0] > 0; --a[0])
            if(a[a[0]]) return ;
    }
    inline void print()
    {
        for(int i = a[0]; i > 0; --i)
            printf("%d", a[i]);
    }
}ans, pow2[MAXN*MAXM];

inline void init()
{
    scanf("%d%d", &n, &m);
    if(n == m) G = n*m*4, check_square = true;
    else G = n*m*2;
    for(int i = 1; i <= n*m; ++i)
        ex[i] = i;
}

inline int calc()
{
    int re = 0;
    bool hash[MAXN*MAXM] = {false};
    for(int i = 1; i <= n*m; ++i)
        if(!hash[i])
        {
            for(int j = i; !hash[j]; j = ex[j])
                hash[j] = true;
            re++;
        }
    return re;
}

inline void rotate()
{
    int nex[MAXN*MAXM] = {0};
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            nex[(m-j)*n+i] = ex[(i-1)*m+j];
    for(int i = 1; i <= n*m; ++i) ex[i] = nex[i];
    swap(n, m);
}

inline void shift_down()
{
    int nex[MAXN*MAXM] = {0};
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            nex[(i%n)*m+j] = ex[(i-1)*m+j];
    for(int i = 1; i <= n*m; ++i) ex[i] = nex[i];
}

inline void shift_right()
{
    int nex[MAXN*MAXM] = {0};
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            nex[(i-1)*m+j%m+1] = ex[(i-1)*m+j];
    for(int i = 1; i <= n*m; ++i) ex[i] = nex[i];
}

inline void work()
{
    pow2[0].a[0] = pow2[0].a[1] = 1;
    for(int i = 1; i <= n*m; ++i)
    {
        bigNum tmp = pow2[i-1];
        tmp += pow2[i-1];
        pow2[i] = tmp;
    }
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
            ans += pow2[calc()];
            rotate();
            if(check_square) ans += pow2[calc()];
            rotate();
            ans += pow2[calc()];
            rotate();
            if(check_square) ans += pow2[calc()];
            rotate();
            shift_right();
        }
        shift_down();
    }
    ans /= G;
}

inline void print()
{
    ans.print();
    puts("");
}

int main()
{
    init();
    work();
    print();
    return 0;
}
时间: 2024-10-14 14:11:55

sgu208:Toral Tickets(Pólya定理)的相关文章

【BZOJ1478】Sgu282 Isomorphism P&#243;lya定理神题

[BZOJ1478]Sgu282 Isomorphism 题意:用$m$种颜色去染一张$n$个点的完全图,如果一个图可以通过节点重新标号变成另外一个图,则称这两个图是相同的.问不同的染色方案数.答案对$P$取模. $n\le 53,m\le 1000,P>n,P$是质数. 题解:对于本题来说,每个元素是所有边,每个置换是边的置换,而边的置换难以表示,点的置换容易表示,所以我们考虑点置换和边置换的关系. 如果两个点置换有着相同的结构,则它们对应的边置换的循环数相同. $$\begin{pmatri

【POJ2409】Let it Bead P&#243;lya定理

[POJ2409]Let it Bead 题意:用$m$种颜色去染$n$个点的环,如果两个环在旋转或翻转后是相同的,则称这两个环是同构的.求不同构的环的个数. $n,m$很小就是了. 题解:在旋转$i$次后,循环节的个数显然是$gcd(i,n)$. 如果考虑翻转,我们将点从$0$到$n-1$标号,令其先以0到圆心的连线为对称轴翻转,再旋转i次,则原来编号为x的会变成$n-x+i?\mathrm{mod}?n$,令$n-x+i=x?\mathrm{mod}?n$,则$2x=i$或$2x=n+i$.

置换及P&#243;lya定理

听大佬们说了这么久Pólya定理,终于有时间把这个定理学习一下了. 置换(permutation)简单来说就是一个(全)排列,比如 \(1,2,3,4\) 的一个置换为 \(3,1,2,4\).一般地,我们记 \(i\) 到 \(a_i(1<=i<=n)\) 的一个置换为 \[ \left ( \begin{matrix} 1 & 2 & \cdots & n \a_1 & a_2 & \cdots & a_n \end{matrix} \rig

Burnside 引理 / P&#243;lya 定理

\(A\) 和 \(B\) 为有限集合 \(X=B^A\) 表示所有 \(A\) 到 \(B\) 的映射 \(G\) 是 \(A\) 上的置换群,\(X/G\) 表示 \(G\) 作用在 \(X\) 上的等价类的集合 \(X^g=\{x|x\in X,g(x)=x\}\) Burnside 引理 \[ |X/G|=\frac{1}{|G|}\sum_{g\in G}|X^g| \] \(c(g)\) 表示置换 \(g\) 能拆分成的不相交的循环置换的数量 Pólya 定理 \[ |X/G|=\f

POJ 2409 Let it Bead P&#243;lya定理

题目大意:给定一个n个点的环,可以旋转和翻转,要求涂上c种不同的颜色,问等价类数目 首先我们不考虑翻转 假设一次旋转k个位置 那么循环个数显然是Gcd(n,i) 现在考虑翻转 易知所有的置换都可以由[沿着某个固定的对称轴翻转]和[旋转]两步组成 观察一个环 比如我们将对称轴设定为1号节点与圆心的连线 一次旋转k个位置 那么每次置换x会被换到((n+2)-x+k-1)%n+1的位置 我们会发现置换两次之后x就回到了原位 乍一看每个置换都是(AB)(CD)(EF)这样的形式 但是我们忽视了可能一个点

【SPOJ419】Transposing is Fun P&#243;lya定理+欧拉函数

[SPOJ419]Transposing is Fun 题意:给你一个$2^a\times2^b$的矩阵,将$1...n$中的数依次从左到右,从上往下填到矩阵里,再把矩阵转置,然后把所有数从左到右,从上往下拿出来得到一个新的排列$A$.你现在每次可以交换两个数,问你从$1...n$变成排列$A$最少要进行多少次操作. 询问次数$\le400000,a+b\le 10^6$ 题解:首先我们可以找到所有的循环节,如果一个循环节中有$x$个数,需要交换$x-1$次.所以我们只需要求出循环节的个数$k$

数学计数原理(P&#243;lya,高精度):SGU 294 He&#39;s Circles

He's Circles He wrote n letters "X" and "E" in a circle. He thought that there were 2n possibilities to do it, because each letter may be either "X" or "E". But Qc noticed that some different sequences of letters ca

poj1286

Necklace of Beads Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7733   Accepted: 3234 Description Beads of red, blue or green colors are connected together into a circular necklace of n beads ( n < 24 ). If the repetitions that are pro

ACM知识点总结

1 枚举 2 模拟 3 构造 4 位运算的应用 5 查找 5.1 二分查找 5.2 分块查找 5.3 哈希查找HASH 5.3.1 线性探测法 5.3.2 字符串与哈希 6 搜索 6.1 深度优先搜索DFS 6.1.1 剪枝 6.1.2 人工栈DFS 6.2 宽度优先搜索BFS 6.3 启发式搜索 7 贪心法 7.1 哈夫曼树 8 高精度 8.1 大数加减法 8.2 大数乘法 8.3 大数除法与取余 9 排序问题 9.1 冒泡排序 9.2 选择排序 9.3 插入排序 9.4 快速排序 9.5 归