zoukankan      html  css  js  c++  java
  • 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!
    ");
            else
                printf("NO!
    ");
        }
        return 0;
    }
  • 相关阅读:
    程序员学习方法差在哪里
    解析域名
    tomcat下的公共jar包配置
    Ubuntu 16.04 修改状态栏位置
    sqlite3 C语言 API 函数
    vim配置文件
    关于 ioctl 函数
    字符设备基础了解
    Ubuntu14.04搭建Boa服务
    gcc 交叉工具链中工具使用(arm-linux-xxx)
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4526555.html
Copyright © 2011-2022 走看看