POJ2154 Color【Polya定理】【欧拉函数】【整数快速幂】

题目链接:

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

题目大意:

给定 N 种颜色的珠子,每种颜色珠子的个数均不限,将这些珠子做成长度为 N 的项链。

问能做成多少种不重复的项链,最后结果对 P 取模。并且两条项链相同,当且仅当两条

项链通过旋转后能重合在一起,且对应珠子的颜色相同。

解题思路:

Polya定理的应用。先来看Polya定理。

Polya定理:设 G = {a1,a2,…,ag}是 N 个对象的置换群,用 M 种颜色给这 N 个

对象着色,则不同的着色 方案数为:

|G|^(-1) * {M^c(a1) + M^c(a2) + … + M^c(ag)}。

其中 c(ai)为置换 ai 的循环节数,( i = 1,2,…,g )。

对于这道题,直接用Polya定理求解,找出所有的置换,并求出置换的循环节数。然后

根据上边公式求出 M^c(ai) 的总和,再除以置换群个数。

旋转置换:分别顺时针旋转 i 个珠子,其循环节长度为 LCM(N,i) / i,循环节数为

N / (LCM(N,i) / i),即 GCD(N,i)。

方案数为:  N^(-1) * Σ{ N^GCD(N,i) } % P (0 <= i <= N)。

这里的N非常大,按照上边的方法遍历 i 从0 到 N,复杂度太高。

在枚举 i 的时候,会出现很多相同的GCD(N,i) == k,问题变为存在多少个 i,从而使

得GCD(N,i) == k。

求GCD(N,i) == k的个数,其实就是求GCD(N/k,i/k) == 1的个数,答案为phi(N/k)

个。

因为k 为N的约数,则遍历 k 时,只需要从 2 到 sqrt(N) 即可。

方案数为: Σ{ phi(N/k) * N^(k-1) + phi(k) * N^(N/(k-1)) } % P (2 <= k <= sqrt(N))。

注意当 k == sqrt(N) 的时候,只加前部分,不要重复加,详细参考代码。

AC代码:

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

bool IsPrime[50050];
int Prime[8010],Num;

void GetPrime()
{
    Num = 0;
    for(int i = 2; i <= 50000; ++i)
    {
        if(!IsPrime[i])
        {
            Prime[Num++] = i;
            for(int j = 1; j*i <= 50000; ++j)
            {
                IsPrime[i*j] = true;
            }
        }
    }
}

int Euler(int x)
{
    int ans = x;
    for(int i = 0; i < Num && Prime[i]*Prime[i] <= x; ++i)
    {
        if(x % Prime[i] == 0)
        {
            ans = ans / Prime[i] * (Prime[i]-1);
            while(x % Prime[i] == 0)
                x /= Prime[i];

        }
    }
    if(x > 1)
        ans = ans / x * (x-1);
    return ans;
}

int QuickMod(int a,int b,int m)
{
    int ans = 1 % m;
    a %= m;
    while(b > 0)
    {
        if(b & 1)
            ans = ans * a % m;
        a = a * a % m;
        b >>= 1;
    }
    return ans;
}

int main()
{
    int T,N,P;
    GetPrime();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&N,&P);
        int ans = 0;
        for(int i = 1; i*i <= N; ++i)
        {
            if(i*i == N)
                ans = (ans + Euler(i)%P *QuickMod(N,i-1,P)) %P; //不要重复加
            else if(N % i == 0)
                ans = ( ans + Euler(i)%P * QuickMod(N,N/i-1,P) + Euler(N/i)%P * QuickMod(N,i-1,P) ) % P;
        }

        printf("%d\n",ans);
    }

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 22:21:34

POJ2154 Color【Polya定理】【欧拉函数】【整数快速幂】的相关文章

【poj2154】Color Polya定理+欧拉函数

题目描述 $T$ 组询问,用 $n$ 种颜色去染 $n$ 个点的环,旋转后相同视为同构.求不同构的环的个数模 $p$ 的结果. $T\le 3500,n\le 10^9,p\le 30000$ . 题解 Polya定理+欧拉函数 根据 poj2409 中得到的结论,答案为: $\frac{\sum\limits_{i=1}^nn^{\gcd(i,n)}}n=\sum\limits_{i=1}^nn^{\gcd(i,n)-1}$ 由于 $n$ 有 $10^9$ 之大,因此考虑优化这个式子. 枚举

Polya 定理入门[Burnside引理,Polya定理,欧拉函数]

$这篇blog重点讨论Polya的应用, 更详细的证明请百度 .$ ___ $Burnside引理$ $$L=\frac{1}{|G|}\sum_{i=1}^{|G|}D(a_i)$$ $L$: 本质不同的方案数. $G$: 置换群集合. $a_i$: 置换群中的第 $i$ 个置换. $D(a_i)$: 进行 $a_i$ 这个置换, 状态不会变化的方案 数量. 该引理与下方内容没有太大关系, 可以暂时忽略. ___ $Problem$ 链接 有 $N$ 个石子围成一圈, 使用 $M$ 种颜色染色

poj2054Color polya定理+欧拉函数优化

没想到贱贱的数据居然是错的..搞得我调了一中午+晚上一小时(哦不d飞LJH掉RP毕竟他是BUFF)结果重判就对了五次.. 回归正题,这题傻子都看得出是polya定理(如果你不是傻子就看这里),还没有翻转,就一个旋转,结果我就欢快的打完交上去了.傻子都知道会TLE,n<=1e9啊,O(n)都原地爆炸,那怎么办...一脸懵逼(然后就膜题解了) 可以发现,这题公式就是sigma(gcd(k,n))(k=1~n),然后该怎么优化呢,我(??)发现gcd(k,n)里面肯定有一些k和n的gcd是相同的,那我

hdu 2837 Calculation【欧拉函数,快速幂求指数循环节】

欢迎关注__Xiong的博客: http://blog.csdn.net/acmore_xiong?viewmode=list Calculation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1912    Accepted Submission(s): 413 链接:click me Problem Description A

Luogu4980 【模板】Polya定理(Polya定理+欧拉函数)

对于置换0→i,1→i+1--,其中包含0的循环的元素个数显然是n/gcd(i,n),由对称性,循环节个数即为gcd(i,n). 那么要求的即为Σngcd(i,n)/n(i=0~n-1,也即1~n).考虑枚举gcd.显然gcd(i,n)=x在该范围内解的个数是φ(n/x).分解一下质因数即可. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<c

poj 2154 Color(polya计数 + 欧拉函数优化)

http://poj.org/problem?id=2154 大致题意:由n个珠子,n种颜色,组成一个项链.要求不同的项链数目,旋转后一样的属于同一种,结果模p. n个珠子应该有n种旋转置换,每种置换的循环个数为gcd(i,n).如果直接枚举i,显然不行.但是我们可以缩小枚举的数目.改为枚举每个循环节的长度L,那么相应的循环节数是n/L.所以我们只需求出每个L有多少个i满足gcd(i,n)= n/L,就得到了循环节数为n/L的个数.重点就是求出这样的i的个数. 令cnt = gcd(i,n) =

POJ2154 Color polya定理+欧拉定理

由于这是第一天去实现polya题,所以由易到难,先来个铺垫题(假设读者是看过课件的,不然可能会对有些“显然”的地方会看不懂): POJ1286 Necklace of Beads :有三种颜色,问可以翻转,可以旋转的染色方案数,n<24. 1,n比较小,恶意的揣测出题人很有可能出超级多组数据,所以先打表. 2,考虑旋转: for(i=0;i<n;i++) sum+=pow(n,gcd(n,i)); 3,考虑翻转: if(n&1) sum+=n*pow(3,n/2+1) ; else {

poj2409 &amp; 2154 polya计数+欧拉函数优化

这两个题都是项链珠子的染色问题 也是polya定理的最基本和最经典的应用之一 题目大意: 用m种颜色染n个珠子构成的项链,问最终形成的等价类有多少种 项链是一个环.通过旋转或者镜像对称都可以得到置换 旋转可以旋转 i=[1,n]次..画图可以看出循环节有gcd(n,i)个 镜像对称的置换画个图也是很容易找的 然后通过polya定理就可以容易的求出等价类的种数了 2409就是这样一个裸题,以下为ac代码 #include <iostream> #include <stdio.h> #

POJ2154 Color(Polya定理)

Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11654   Accepted: 3756 Description Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of the nec

费马小定理,欧拉函数

在证明这些定理之前先证明一个有意思的定理. 对于0 mod m,n mod m , 2n mod m, 3n mod m, 4n mod m... (m-1)n mod m 对应解集序列 一定有 m/d份 0 d 2d 3d..m-d. (不一定按照顺序) 这样的解. 其中d = gcd(n,m) 具体点:n=8,m=12.  d = gcd(n,m)=4 对于 0 mod 12,8 mod 12,16 mod 12,24 mod 12,32 mod 12,40 mod 12...88 mod