现在的位置: 首页 > 综合 > 正文

POJ 2154 Color

2013年10月08日 ⁄ 综合 ⁄ 共 1886字 ⁄ 字号 评论关闭

Ploya定理+数论知识...

置换群是由旋转置换构成的,因此|G| = n

基本知识:循环的个数为gcd(i,n),循环的长度为l = n/gcd(i,n)      ans = sigma(n^(gcd(n,i)-1))  1<=i<=n

由于n很大所以需要利用欧拉函数进行优化。。。

枚举的方法有两种:

<1>将n进行质因子分解,然后根据质因子分解枚举它的约数ys,这样答案便为sigma(euler(n/ys)*n^(ys-1))

<2>枚举循环的长度l,答案为 sigma(euler(l)*n^(n/l-1))

我采用的是第一种枚举的方法,比第二种方法稍微繁琐一些,不过都很简单啦。。。

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 60000;
bool is_prime[MAXN];
ll prime[MAXN];
ll facs[110], ccount[110];
ll ans, N, P;
int len, cnt, x;

void Init()
{
    int i, j;
    len = 0;
    memset(is_prime, true, sizeof(is_prime));
    is_prime[0] = is_prime[1] = false; prime[len++] = 2;
    for(i = 4; i < MAXN; i += 2)
        is_prime[i] = false;
    for(i = 3; i * i <= MAXN; i += 2)
    {
        if(is_prime[i])
        {
            prime[len++] = i;
            for(j = i * i; j < MAXN; j += i)
                is_prime[j] = false;
        }
    }
    for( ; i < MAXN; ++i)
        if(is_prime[i])
            prime[len++] = i;
}


ll gcd(ll a, ll b)
{
    if(b == 0)
        return a;
    return gcd(b, a % b);
}

ll mul_mod(ll a, ll b, ll c)
{
    ll ret = 0;
    while(b)
    {
        if(b & 1)
            ret = (ret + a) % c;
        a = a * 2 % c;
        b >>= 1;
    }
    return ret;
}

ll power_mod(ll a, ll b, ll c)
{
    ll ret = 1;
    while(b)
    {
        if(b & 1)
            ret = mul_mod(ret, a, c);
        a = mul_mod(a, a, c);
        b >>= 1;
    }
    return ret;
}

void cal(ll n)
{
    cnt = 0;
    memset(ccount, 0, sizeof(ccount));

    for(int i = 0; i < len && prime[i]*prime[i] <= n; ++i)
    {
        if(n % prime[i] == 0)
        {
            facs[cnt] = prime[i];
            while(n % prime[i] == 0)
            {
                ccount[cnt]++;
                n /= prime[i];
            }
            cnt++;
        }
    }
    if(n > 1)
        facs[cnt] = n, ccount[cnt++] = 1;
    return ;
}

ll euler(ll n)
{
    ll ret = n;
    for(int i = 0; i < len && prime[i]*prime[i] <= n; ++i)
    {
        if(n % prime[i] == 0)
        {
            ret = ret/prime[i]*(prime[i]-1);
            while(n % prime[i] == 0)
            {
                n /= prime[i];
            }
        }
    }
    if(n > 1)
        ret = ret/n*(n-1);
    return ret;
}

ll power(ll a, ll b)
{
    ll ret = 1;
    while(b)
    {
        if(b & 1)
            ret = ret * a;
        a = a * a;
        b >>= 1;
    }
    return ret;
}

void dfs(ll cur, int id)
{
    if(id == cnt)
    {
        ans = (ans + euler(N/cur)*power_mod(N, cur-1, P)) % P;
        return ;
    }
    for(int i = 0; i <= ccount[id]; ++i)
    {
        dfs(cur*power(facs[id], i), id + 1);
    }
    return ;
}

int main()
{
    //freopen("aa.in", "r", stdin);
    //freopen("bb.out", "w", stdout);

    Init();
    cin >> x;
    while(x--)
    {
        cin >> N >> P;
        if(N == 1)
        {
            cout << N % P << endl;
            continue;
        }
        ans = 0;
        cal(N);
        dfs(1, 0);
        cout << ans << endl;
    }
    return 0;
}

抱歉!评论已关闭.