SOJ 1038

1038. EKG Sequence

Constraints

Time Limit: 5 secs, Memory Limit: 32 MB

Description

The EKG sequence is a sequence of positive integers generated as follows: The first two numbers of the sequence are 1 and 2. Each successive entry is the smallest positive integer not already used that shares a factor with the preceding term. So, the third entry in the sequence is 4 (being the smallest even number not yet used). The next number is 6 and the next is 3. The first few numbers of this sequence are given below.

1, 2, 4, 6, 3, 9, 12, 8, 10, 5, 15, 18, 14, 7, 21, 24, 16, 20, 22, 11, 33, 27

The sequence gets its name from its rather erratic fluctuations. The sequence has a couple of interesting, but non-trivial, properties. One is that all positive integers will eventually appear in the sequence. Another is that all primes appear in increasing order. Your job here is to _nd the position in the sequence of a given integer.

Input

Input consists of a number of test cases. Each case will be a line containing a single integer n, 1 <= n <= 300000. An input of 0 follows the last test case. Note that the portion of the EKG sequence that contains all integers <= 300,000 will not contain an integer >1,000,000.

Output

Each test case should produce one line of output of the form:

The number n appears in location p.

where n is the number given and p is the position of n in the EKG sequence. You are guaranteed that p will be no larger than 1,000,000.

Sample Input

12
21
2
33
100000
299977
0

Sample Output

The number 12 appears in location 7.
The number 21 appears in location 15.
The number 2 appears in location 2.
The number 33 appears in location 21.
The number 100000 appears in location 97110.

The number 299977 appears in location 584871.

这个题更偏向数学问题,主要难点也就是如何通过上一个数确定下一个数的值。假设我们已知上一个数,这个数的素因子有p1,p2,p3,先以p1为两个数的公因子,然后对p1一直增加一倍,直到这个倍数未出现过,记为a1,然后同样地求出a2,a3,那么a1a2a3中最小的那个就是下一个数的结果。具体算法见代码吧。

// Problem#: 1038
// Submission#: 5060802
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include<iostream>
#include<cmath>
using namespace std;
#define maxn 1000000
int location[maxn];//位置数组,location[i]表示数字i在EKG数列中的位置 
int smallest_prime[maxn];//保存最小素数,即smallest_prime[i]保存i的最小素因数 
int next_number[maxn];//next_number[i]保存i尚未在数列中出现过的最小倍数 

void makeSequence()
{
    location[1]=1;//1和2的位置题目已经给出 
    location[2]=2;
    for(int i=2;i<maxn;++i)
    {
        if(smallest_prime[i]==0)//找出大于1的每个数的最小素因数 
        {
            for(int j=1;i*j<maxn;++j)
            {
                if(smallest_prime[i*j]==0)
                    smallest_prime[i*j]=i;
            }
        }
    } 
    for(int i=1;i<maxn;++i)//初始时数列还未开始构造,所以每个数不在数列中的最小倍数为自身 
        next_number[i]=i;
    int current_number=2;//currentnumber保存最新确定的数列元素 
    int smallPrime,temp;
    for(int i=3;i<maxn;++i)//现在开始求下一个数的值 
    {
        temp=current_number;//先将值赋给temp,currentnumber要始终保存最新找到的值 
        current_number=maxn;
        while(temp!=1)//主要原理为先找出上个数的最小素因子,并以其作为公因子,寻找最小素因子尚未出现过的最小倍数,然后再找上个数的次小素因子,再以次小素因子作为公因子寻找其尚未出现的最小倍数,依此类推,直到上个数的所有素因子都寻找一遍,然后选择所有结果中最小的那个作为下一个数 
        {
            smallPrime=smallest_prime[temp];//temp为上个数的某个素因子 
            while(location[next_number[smallPrime]]!=0&&next_number[smallPrime]+smallPrime<maxn)//若这个素因子已经出现过,则将最小素因子增加一倍,直到不在数列中出现 
                next_number[smallPrime]+=smallPrime;
            current_number=min(current_number,next_number[smallPrime]);//寻找每个素因子求出结果的最小值 
            while(temp%smallPrime==0)//寻找上个数的下一个素因子,若temp==1则代表已经全部找完 
                temp/=smallPrime;
        }
        location[current_number]=i;
    }
}
int main()
{
    int n;
    makeSequence();
    while(cin>>n&&n)
    {
        cout<<"The number "<<n<<" appears in location "<<location[n]<<'.'<<endl;
    }
    return 0;
}                                 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值