素数筛法,欧拉公式

素数筛法,欧拉公式

Counting fractions

TimeLimit: 2000MS  MemoryLimit: 65536 Kb

Totalsubmit: 39   Accepted: 6  

Description

Consider the fraction, n/d, where n and d are positive integers. If <= d and HCF(n,d)=1, it is called a reduced proper fraction.

If we list the set of reduced proper fractions for d <= 8 in ascending order of size, we get:

1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8

It can be seen that there are 21 elements in this set.

How many elements would be contained in the set of reduced proper fractions for d <= x?

Input

The input will consist of a series of x, 1 < x < 1000001.

Output

For each input integer x, you should output the number of elements contained in the set of reduced proper fractions for d <= x in one line.

Sample Input

3

8

Sample Output

3
21

Hint

HCF代表最大公约数

这里主要说一下 素数筛法,该方法可以快速的选取出1~N数字中的所有素数。时间复杂度 远小于O(N*sqrt(N))
方法为:从2开始,往后所有素数的倍数都不是素数。最后剩下的数都是素数。
再说说欧拉公式,用来解决所有小于n中的数字有多少个与n互质,用Ψ(n)表示。
Ψ(n)=n*(1-1/q1)*(1-1/q2)*……*(1-1/qk),n为和数,其中qi为n的质因数。
Ψ(n)=n-1,n为质数
注意:关于数论的题很容易超过int类型的范围,多考虑用long long类型。
欧拉函数请参阅: http://zh.wikipedia.org/zh-cn/%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0

代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define LEN 1100010
using namespace std;
int len0 = (int)sqrt(LEN);
int isp[LEN];//isprime?
int pr[LEN];//依次记录素数
int pct;// prime count
long long rs[LEN];//fi(n)
int main()
{
    int i, j;
    int x;
    memset(isp, -1, sizeof(isp));
    for(int i = 2; i <= len0; i++)//素数筛法选出素数
    {
        if(isp[i])
        {
            for(int j = i * 2; j < LEN; j += i)
                isp[j] = 0;
        }
    }
    pct = 0;
    for(int i = 2; i < LEN; i++)//记下选出的素数
        if(isp[i])
            pr[pct++] = i;

    for(int i = 0; i < LEN; i++)
        rs[i] = i;
    for(int i = 0; i < pct; i++)
    {
        rs[pr[i]]--;
        for(int j = pr[i] * 2; j < LEN; j += pr[i])
        {
            rs[j] = rs[j]  / pr[i] * (pr[i] - 1);//rs[]要定义成long long类型,因为计算过程中乘法会超过int类型的取值范围
            
//rs[j] -= rs[j] / pr[i];
        }
    }
    while(scanf("%d", &x) != EOF)
    {
        long long sum = 0;
        for(int i = 2; i <= x; i++)
            sum += rs[i];
        //printf("%lld\n", sum);
        cout << sum << endl;//用cout输出,不用考虑使用%lld还是%I64d
    }
    //system("pause");
    return 0;
}

 

你可能感兴趣的:(素数筛法,欧拉公式)