这个题暴露了自己很严重的基础知识问题==就是二分啊!因为自己知道当年(就是去年这会)二分学的不好,都一年了,还能怨人家课件吗??
于是乎在网上搜呀搜,搜到了点击打开链接 这篇博客,说的简直就是自己啊啊啊啊,还好给了模板,也非常好理解,顺便测试了一下
#include <iostream> #include<cstdio> using namespace std; int num[10]={1,1,2,2,4,4,5,5,7,7}; /**************** answer: 1~YES_LEFT或者NO_RIGHT~is 1 1~YES_RIGHT或者NO_LEFT~is 2 2~YES_LEFT或者NO_RIGHT~is 3 2~YES_RIGHT或者NO_LEFT~is 4 3~YES_LEFT或者NO_RIGHT~is 5 3~YES_RIGHT或者NO_LEFT~is 4 4~YES_LEFT或者NO_RIGHT~is 5 4~YES_RIGHT或者NO_LEFT~is 6 5~YES_LEFT或者NO_RIGHT~is 7 5~YES_RIGHT或者NO_LEFT~is 8 6~YES_LEFT或者NO_RIGHT~is 9 6~YES_RIGHT或者NO_LEFT~is 8 7~YES_LEFT或者NO_RIGHT~is 9 7~YES_RIGHT或者NO_LEFT~is 10 *****************/ int bSearch1(int begin, int end, int e)///YES_LEFT或者NO_RIGHT { int mid, left = begin, right = end; while(left <= right) { mid = (left + right) >> 1; if(num[mid] >= e) right = mid - 1; else left = mid + 1; } return left; } int bSearch2(int begin, int end, int e)///YES_RIGHT或者NO_LEFT { int mid, left = begin, right = end; while(left <= right) { mid = (left + right) >> 1; if(num[mid] > e) right = mid - 1; else left = mid + 1; } return right; } int main() { for(int i=1;i<=7;i++) { printf("%d~YES_LEFT或者NO_RIGHT~is %d\n",i,bSearch1(0,9,i)+1); printf("%d~YES_RIGHT或者NO_LEFT~is %d\n",i,bSearch2(0,9,i)+1); } return 0; }
/*************** hdu4417 2016.1.28 561MS 20228K 2603 B G++ 390MS 20232K 2603B G++ new ***************/ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN=100110; int tree[30][MAXN];//表示每层每个位置的值 int sorted[MAXN];//已经排序的数 int toleft[30][MAXN];//toleft[p][i]表示第i层从1到i有多少个数分入左边 int t,n, m; void build(int l,int r,int dep) { if(l==r)return; int mid=(l+r)>>1; int same=mid-l+1;//表示等于中间值而且被分入左边的个数 for(int i=l;i<=r;i++) if(tree[dep][i]<sorted[mid]) same--; int lpos=l; int rpos=mid+1; for(int i=l;i<=r;i++) { if(tree[dep][i]<sorted[mid])//比中间的数小,分入左边 tree[dep+1][lpos++]=tree[dep][i]; else if(tree[dep][i]==sorted[mid]&&same>0) { tree[dep+1][lpos++]=tree[dep][i]; same--; } else //比中间值大分入右边 tree[dep+1][rpos++]=tree[dep][i]; toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数 } build(l,mid,dep+1); build(mid+1,r,dep+1); } //查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间 int query(int L,int R,int l,int r,int dep,int k) { if(l==r)return tree[dep][l]; int mid=(L+R)>>1; int cnt=toleft[dep][r]-toleft[dep][l-1];//[l,r]中位于左边的个数 if(cnt>=k) { //L+要查询的区间前被放在左边的个数 int newl=L+toleft[dep][l-1]-toleft[dep][L-1]; //左端点加上查询区间会被放在左边的个数 int newr=newl+cnt-1; return query(L,mid,newl,newr,dep+1,k); } else { int newr=r+toleft[dep][R]-toleft[dep][r]; int newl=newr-(r-l-cnt); return query(mid+1,R,newl,newr,dep+1,k-cnt); } } int half(int a,int b,int x) { int l=1,r=b-a+1,mid,ans=0; while(l<=r) { mid=(l+r)/2; int tmp=query(0,n-1,a,b,0,mid); if(tmp<=x) {ans=mid;l=mid+1;} else r=mid-1; } //return ans; return l;//new } int main() { // freopen("cin.txt","r",stdin); int cnt=1; scanf("%d",&t); while(t--) { printf("Case %d:\n",cnt++); memset(tree,0,sizeof(tree)); scanf("%d%d", &n,&m); for (int i=0; i<n; i++) { scanf("%d", &sorted[i]); tree[0][i] = sorted[i]; } sort(sorted, sorted+n); build(0, n-1, 0); int a, b, k; while (m--) { scanf("%d%d%d", &a, &b, &k); //a++;b++; printf("%d\n",half(a,b,k)-1); } } return 0; }