HDU 3486 Interviewe【二分+rmq】
题意: 给出 n 个序列,要求把它分成长度相等的m份,多余的去掉,要求每份的最大值之和大于 k。
问最少要分成多少份。
分析: 二分区间,用rmq预处理出区间最大值。
#include <stdio.h> #include <string.h> #include <math.h> #define max(a,b)(a)>(b)?(a):(b) #define maxn 200005 int val[maxn]; int dp[maxn<<1][20]; int k,n; void makermq() { int i, j; for(i = 1; i <= n; i++) dp[i][0] = val[i]; for(j = 1; (1<<j)<=n; j++) for(i = 1;i+(1<<j)-1<=n; i++) dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } int rmq(int l,int r) { int k = (int)(log((r-l+1)*1.0)/log(2.0)); return max(dp[l][k],dp[r-(1<<k)+1][k]); } int ok(int m) { int en = n,t,sum,i,mod; if(n%m!=0) en-=n%m; mod = n/m; t = sum = 0; for(i = mod; i <= en; i+=mod) { sum += rmq(i-mod+1,i); if(sum > k) return 1; } return sum>k; } inline bool scan_d(int &num) { char in; bool IsN=false; in=getchar(); if(in==EOF) return false; while(in!='-'&&(in<'0'||in>'9')) in=getchar(); if(in=='-'){ IsN=true;num=0;} else num=in-'0'; while(in=getchar(),in>='0'&&in<='9'){ num*=10,num+=in-'0'; } if(IsN) num=-num; return true; } int main() { int i; int l, r, mid, res; while(scanf("%d %d",&n, &k)!=EOF) { if(n<0&&k<0) break; for(i = 1; i <= n; i++) scan_d(val[i]); makermq(); l = 1; r = n; res = -1; while(l<=r) { mid = (l+r)>>1; if(ok(mid)){ res = mid; r = mid-1; } else l = mid+1; } printf("%d\n",res); } return 0; }