ACM学习历程—HDU1719 Friend(数论)

Description

Friend number are defined recursively as follows.
(1) numbers 1 and 2 are friend number;
(2) if a and b are friend numbers, so is ab+a+b;
(3) only the numbers defined in (1) and (2) are friend number.
Now your task is to judge whether an integer is a friend number.
 

Input

There are several lines in input, each line has a nunnegative integer a, 0<=a<=2^30.
 

Output

For the number a on each line of the input, if a is a friend number, output “YES!”, otherwise output “NO!”.
 

Sample Input

3
13121
12131
 

Sample Output

YES!
YES!
NO!

 

由题意,如果n = a+b+ab,a和b都是friend number

那么(n+1) = (a+1) * (b+1),

然后我记friend number叫做好数。

那么2和3是好数。

然后两个好数相乘也是好数。

由于其他数首先都是由2和3生出的,所以好数必然是2^k * 3^p。

接下来证明所有2^k * 3^p都是好数。

反证:

若2^k * 3^p不是好数,那么2^(k-1) * 3^p必然也不是好数,否则2^(k-1) * 3^p和2相乘会导致2^k * 3^p也是好数。

然后递降下来说明了3^p也不是好数。

同理说明了3不是好数。

矛盾!

所以所有2^k * 3^p都是好数。

于是判断好数只需要先把二因子除去,这里采用位运算优化。

然后除去3因子,判断最后结果是不是1。这里打表保存了3的所有指数密进行判断。

能判断好数了,自然能判断friend number了。不过需要对0进行特判。

 

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

#include <set>

#define LL long long



using namespace std;



const int maxn = 1<<30;



set <LL> s;



void Init()

{

    int now = 2;

    s.insert(1);

    for (;;)

    {

        if (now > maxn)

            break;

        s.insert(now);

        now = 2*now + 1;

    }

    now = 5;

    for (;;)

    {

        if (now > maxn)

            break;

        s.insert(now);

        now = 3*now + 2;

    }



    now = 11;

    for (;;)

    {

        if (now > maxn)

            break;

        s.insert(now);

        now = 6*now + 5;

    }

}



bool judge(LL n)

{

    if (no.find(n) != no.end())

        return false;

    if (s.find(n) != s.end())

        return true;

    n++;

    int len = sqrt(n);

    for (int i = 2; i <= len; ++i)

    {

        if (n % i)

            continue;

        if (judge(i-1)&&judge(n/i-1))

        {

            s.insert(n);

            return true;

        }

    }

    no.insert(n);

    return false;

}



int main()

{

    //freopen("test.in", "r", stdin);

    LL n;

    Init();

    while (scanf("%I64d", &n) != EOF)

    {

        if (judge(n))

            printf("YES!\n");

        else

            printf("NO!\n");

    }

    return 0;

}

 

你可能感兴趣的:(ACM)