1. 程式人生 > >一生之敵-2017浙江中醫藥大學程式設計

一生之敵-2017浙江中醫藥大學程式設計

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 131072K,其他語言262144K

64bit IO Format: %lld   

題目描述

大家都知道Alice和Bob兩個人是一生之敵。(霧   但某天,他們兩個人發了瘋。想知道他們兩個是否可以成為朋友。  
於是他們做了一個令人窒息的決定。    
Alice和Bob每個人任意選一個整數。  
假設Alice選擇了整數a,Bob選擇了整數b。  
Alice使得a做如下變換:  
a -> 2 * a * (a+1)^2
Bob使得b做如下變換:  
b -> b^2
如果變換後的數字相等,則兩個人可以化敵為友。  
如果不相等,這兩個人怕是石樂志。
現在,你想把Bob部分可能的整數b(存在a變換後的數字等於b變換後的數字)從小到大排列後,知道第一個大於等於n的數字是多少。

輸入描述:

第一行輸入一個整數T,表示資料組數。
每組資料輸入一個整數n。
1 <= T <= 100000
0 <= n <= 10^19
保證結果存在

輸出描述:

輸出一個整數。
示例1

輸入

3  
2  
6  
100

輸出

6
6
114

這道題當時讀了很久,一直搞不懂樣例是怎麼出來,還是做的題少,沒有語感,中文題目都這樣了,何況英文題;

讀懂題意之後,一看資料範圍就知道是二分查詢,只需要把a和b做一下變換即可:

b^2 = 2*a*(a+1)^2 -> b = sqrt(2*a)*(a+1);

因為sqrt(2*a)是整數,所以令2*a=4*t*t,所以a=2*t*t;

所以就轉換成b=2*t*(2*t*t + 1),所以只需二分

#include <stdio.h>
#include <iostream>
using namespace std;
#define MAX 3e6
typedef unsigned long long ULL;

int main() {
	int T;
	cin>>T;
	while(T--) {
		ULL n;
		scanf("%llu",&n);
		if(n == 0) {
			printf("0\n");
			continue;
		}
		ULL l = 0, r = MAX, m, t, ans;
		while(l <= r) {
			m = l+(r-l)/2;
			t = 4*m*m*m + 2*m;
			if(t >= n) {
				ans = t;
				r = m - 1;
			}
			else {
				l = m + 1;
			}
		}
		printf("%llu\n",ans);
	}
	return 0;
}