poj 2154 Color

    这是道标准的数论优化的polya题。卡时卡的很紧,需要用int才能过。程序中一定要注意控制不爆int!!!我因为爆intWA了好久=_=……

    题目简洁明了,就是求 sigma n^gcd(i,n);但是由于n很大,所以直接暴力枚举必然会T。于是我们按照这种题的通常思路按gcd的值分类

    gcd(i, n) = 1 的个数很明显为 phi(n);

    gcd(i, n) = 2 -> gcd(i/2, n/2) = 2 所以个数为 phi(n/2);

    这样就ok了, 我们就是要求 sigma phi(n/d) * n^d , 其中 d 是 n 的因数。

    上代码:

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <iostream>

#include <algorithm>

#include <cmath>

using namespace std;



int n, p;



int mi(int a)

{

    int ans = 1, zan = n%p;

    while (a)

    {

        if (a & 1)

            ans = (ans * zan) % p;

        a >>= 1; zan = (zan * zan) % p;

    }

    return ans;

}



int ouler(int now)

{

    int ans = now;

    for (int i = 2; i*i <= now; ++i)

        if (!(now % i))

        {

            ans = ans / i * (i-1);

            while (!(now % i)) now /= i;

        }

    if (now > 1) ans = ans / now * (now-1);

    return ans;

}



int main()

{ 

    int T; scanf("%d", &T);

    while (T--)

    {

        scanf("%d%d", &n, &p);

        int ans = 0;

        for (int i = 1; i*i <= n; ++i)

            if (!(n % i))

            {

                ans = (ans + ouler(n/i)%p*mi(i-1)) % p; // 两个函数位置一定不能倒过来 

                if (i * i != n)

                ans = (ans + ouler(i)%p*mi(n/i-1)) % p; // 不然会超int!!! 

            }

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

    }

    return 0;

}

 

你可能感兴趣的:(color)