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; }