Project Euler 44 Sub-string divisibility( 二分 )


题意:五边形数由公式Pn=n(3n−1)/2生成,在所有和差均为五边形数的五边形数对Pj和Pk中,找出使D = |Pk − Pj|最小的一对;此时D的值是多少?

思路:二分找和差


/*************************************************************************
> File Name: euler044.c
> Author: WArobot
> Blog: http://www.cnblogs.com/WArobot/
> Created Time: 2017年06月27日 星期二 10时59分39秒
************************************************************************/

include <stdio.h>

include <inttypes.h>

define MAX_N 5000

define MAX_RANGE 37497500

bool Binary_Serch(int32_t n , int32_t *p) { // 判断n是否在数组num[]中
if (n > MAX_RANGE) return false;
int32_t l = 1 , r = MAX_N - 1 , mid;
while (l < r) {
mid = (l + r) >> 1;
if (p[mid] < n) l = mid + 1;
else r = mid;
}
return p[r] == n;
}

int32_t main() {
int32_t p[MAX_N];
for (int32_t i = 1 ; i < MAX_N ; i++) {
p[i] = ( 3 * i * i - i ) / 2;
}
int32_t ans = MAX_RANGE + 10;
bool flag = false;
for (int32_t k = 1 ; k < MAX_N ; k++) { // p[k] > p[j] k 从小到大枚举 j 从大到小枚举
for (int32_t j = k - 1 ; j >= 1 ; j--) {
if (!Binary_Serch(p[k] + p[j] , p)) continue;
if (!Binary_Serch(p[k] - p[j] , p)) continue;
if (ans > p[k] - p[j]) { // 假如 ans已经被 p[k] - p[j] 更新完成那就没必要向下继续枚举j,因为向下枚举j时D肯定不会被更新
ans = p[k] - p[j]; flag = true;
break;
}
}
if (flag) break; // 如果 ans已经被更小的 p[k] - p[j] 更新过一次,那就没有必要继续枚举k了,因为向上继续枚举k并不会让D更小
}
printf("%d\n",ans);
return 0;
}


方法二:

/*************************************************************************
	> File Name: test.cpp
	> Author: 
	> Mail: 
	> Created Time: 2018年02月03日 星期六 08时42分28秒
 ************************************************************************/

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

ll Pentagonal(ll n) {
    return n * (n * 3 - 1) / 2;
}
bool isPentagonal(ll n) {
    int l = 1, r = n, mid;
    while (l <= r) {
        mid = (l + r) >> 1;
        ll t = Pentagonal(mid);
        if (t == n) {
            return true;
        } else if (t < n) {
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    return false;
}

int main() {
    ll ans = INT_MAX;
    ll n = 1, m, p1, p2;
    while (true) {
        p1 = Pentagonal(n);
        p2 = Pentagonal(n - 1);
        if (p1 - p2 > ans) break;
        for (int m = n - 1 ; m >= 1 ; --m) {
            p2 = Pentagonal(m);
            if (p1 - p2 >= ans) break;
            if (isPentagonal(p1 + p2) && isPentagonal(p1 - p2)) {
                ans = p1 - p2;
            }
        }
        ++n;
    }
    printf("ans is %lld\n", ans);
    return 0;
}
posted @ 2017-06-27 11:42  ojnQ  阅读(218)  评论(0)    收藏  举报