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

POJ-2773-Happy 2006 解题报告

2018年04月21日 ⁄ 综合 ⁄ 共 1196字 ⁄ 字号 评论关闭

       欧拉函数好题。题意:给你一个数m,请你输出从1开始升序排列与m互素的数列中的第k个数。


       我的解题思路:根据数据范围,K最大可以达到1E,比m还大,因此很容易想到数据会超过32位整型。而且要找m的第k个与m互素的数肯定不能用暴力枚举的办法。

两个互素的数a,b它们满足gcd(a,b) = 1这个条件,根据gcd的这么一个性质gcd(a,b) = gcd(b,a%b)即gcd(a,b) = gcd(b, a + nb),其中n可以为任意非负整数。从这里我们可以发现一个规律那就是与b互质的数是有周期规律的,如果第一个周期与b互素的数列为[1, ... , x](x <= b),那么第二个周期与b互素的数列就是[1 + b, ... , x + b],第三个周期就是[1 + 2b, ...,
x + 2b],因此我们可以通过算出小于等于b与b互素的数列来推出所有与b互素的数了。

运用到这道题上,先求出小于等于m与m互素的数以及它们的个数即m的欧拉函数值,然后就可以算出第k个与m互素的数在第几个周期上,从而算出对应的数。


       我的解题代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>

using namespace std;

typedef long long Long;

const Long N = 1000001;

bool m_prime[N];    //判断是否与m互素
Long m, k;

void DataProcess();

Long Phi(Long x);   //计算欧拉函数的同时标记不与m互素的数

int main()
{
    while (~scanf("%lld %lld", &m, &k))
    {
        DataProcess();
    }
    return 0;
}

void DataProcess()
{
    memset(m_prime, true, sizeof(m_prime));
    Long n = Phi(m);
    Long cnt = 0;
    Long key = k % n == 0 ? n : k % n;
    Long tmp = (k - 1) / n;     //计算周期
    for (Long i=1; i<=m; ++i)
    {
        if (m_prime[i] && ++cnt == key)
        {
            printf("%lld\n", i + tmp * m);
            break;
        }
    }
    return;
}

Long Phi(Long x)
{
    Long ans = x;
    Long cnt = (Long)sqrt(x + 0.5) + 1;
    for (Long i=2; i<cnt; ++i)
    {
        if (x % i == 0)
        {
            ans -= ans / i;
            while (x % i == 0) x /= i;
            for (Long j=i; j<N; j+=i) m_prime[j] = false;
        }
    }
    if (x > 1)
    {
        ans -= ans / x;
        for (Long j=x; j<N; j+=x) m_prime[j] = false;
    }
    return ans;
}

抱歉!评论已关闭.