二分搜索典例
題目:http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=612
?
題意:給一個正整數n,n小于10^8,對于X^X達到n位時,求最小的X,注意是達到n。
?
分析:先求出第一個滿足X^X的位數大于等于n位的X,然后從上到下枚舉X,如果X^X的位數小于n時就break。那么i+1就是答案。
?
?
題目:http://codeforces.com/contest/325/problem/B
?
題意:給一個正整數n<=10^18,m是奇數,求的解有多少個,并按從小到大的順序輸出所有的。
?
分析:方法就是枚舉k,二分m。
#include <iostream> #include <string.h> #include <algorithm> #include <stdio.h>using namespace std; typedef long long LL; const int N = 1005; const LL INF = 1e18; const LL R = 3*1e9;LL S[N]; int cnt;void Binary_Search(LL n) {for(int k=0;k<63;k++){LL l = 1;LL r = R;if(k >= 30) r = INF >> k;while(l <= r){LL m = (l + r) >> 1;LL ans = (((LL)1 << k) - 1) * m * 2 + m * (m - 1);if(ans > 2*n) r = m - 1;else if(ans < 2*n) l = m + 1;else{if(m&1) S[cnt++] = m * ((LL)1 << k);break;}}} }int main() {LL n;cin>>n;cnt = 0;Binary_Search(n);sort(S,S+cnt);if(cnt == 0) puts("-1");else{for(int i=0;i<cnt;i++)cout<<S[i]<<endl;}return 0; }
?
?
題目:http://acm.hdu.edu.cn/showproblem.php?pid=4282
?
題意:對于方程X^Z + Y^Z + XYZ = K,已知K求此方程解的個數,其中要求X<Y,Z>1,而K的范圍是0到2^31。
?
分析:這道題明顯的二分搜索題。
?
首先我們來分析Z的范圍:由于X,Y為正整數,X < Y,則1 < X < Y, =====>? Y >= 2
=>??X^Z + Y^Z + XYZ > Y^Z??
=>??2^Z <= Y^Z < 2^31
所以得到2 <= Z<31
對于Z=2時我們來特殊處理。所以只分析Z在3<=Z<31的情況。
我們再來分析X的范圍:
對于方程X^Z + Y^Z + XYZ = K, X < Y,則有X^Z + Y^Z + XYZ > 2*X^Z + X*X*Z >= 2*X^3 + 3*X^2
即我們得到:2*X^3 + 3*X^2 < 2^31???解這個方程有:X < 1024
于是現在我們得到了3 <= Z < 31,1 <= X < 1024,當然Z=2特殊處理。接下來就直接枚舉X,Z,來二分Y。
#include <iostream> #include <string.h> #include <stdio.h> #include <math.h>using namespace std; typedef long long LL;LL f[1300][32];void Init() {for(int i=1; i<1300; i++){f[i][0] = 1;for(int j=1; j<31; j++){f[i][j] = f[i][j-1] * i;if(f[i][j] > 2147483648LL)break;}} }bool Binary_Search(int x,int z,int K) {int mid;int l=x+1;int r=1290;while(l <= r){mid = (l + r) >> 1;if(f[mid][z] == 0){r = mid - 1;continue;}LL ret = f[x][z] + f[mid][z] + x * mid * z;if(ret < K)l = mid + 1;else if(ret > K)r = mid - 1;elsereturn true;}return false; }int main() {Init();int K;while(~scanf("%d",&K),K){LL ans = 0;int tmp = (int)sqrt(1.0*K);if(tmp*tmp == K){if(tmp % 2)ans += tmp / 2;elseans += (tmp / 2 - 1);}for(int x=1; x<1024; x++){for(int z=3; z<31; z++){if(f[x][z] == 0) break;if(Binary_Search(x,z,K))ans++;}}printf("%I64d\n",ans);}return 0; }
?
總結