题意:有n个人排队应聘,每个人有一个能力值,然后老板要把这些人分成m段,如果不能整除多出来就后面的人就不要了,然后从这m段里面选择每段的最大能力值加起来看是否能够大于老板需要的目标k,因为薪资问题,尽可能少录取人,所以找出满足条件的最小的m。
输入时找出所有能力值的最大值max,则分组最少为k/max(缩短时间,否则会TLE);然后枚举之后的分组,在每个分组内找最大值(RMQ),sum+=RMQ(L,R);当碰到第一个满足条件的分组时(sum>k),就可以跳出循环,直接输出答案了。
RMQ一般用于求区间最值问题,但是也可以求类似区间gcd这种,不涉及到更新用RMQ会更快一点,否则还是用线段树。
1 #include<iostream> 2 #include<stdio.h> 3 #include<math.h> 4 #include<algorithm> 5 #define LL long long 6 7 using namespace std; 8 9 const int MAX_N = 200005; 10 LL k,n; 11 int num[MAX_N]; 12 int dp[MAX_N][20]; 13 14 void rmq_init() 15 { 16 for(int i = 0; i < n; i++) 17 dp[i][0] = num[i]; 18 for(int j = 1; (1<<j) <= n; j++) 19 { 20 for(int i = 0; i+(1<<j)-1 < n; i++) 21 { 22 dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); 23 } 24 } 25 } 26 27 int rmq(int l,int r) 28 { 29 int k = 0; 30 while(1<<(k+1)<=(r-l+1)) 31 k++; 32 return max(dp[l][k],dp[r-(1<<k)+1][k]); 33 } 34 int main() 35 { 36 while(cin>>n>>k,n>0 || k>=0) 37 { 38 int maxx = 0,sum = 0; 39 for(int i = 0; i < n; i++) 40 { 41 cin>>num[i]; 42 if(num[i]>maxx) 43 maxx = num[i]; 44 sum+=num[i]; 45 } 46 if(sum<k) 47 { 48 cout<<-1<<endl; 49 continue; 50 } 51 rmq_init(); 52 int zu = k / maxx; 53 int peo,new_sum; 54 if(zu==0) 55 zu=1; 56 for(;zu<=n;zu++) 57 { 58 peo = n/zu; 59 new_sum = 0; 60 for(int i = 1; i <= zu; i++) 61 { 62 new_sum+=rmq((i-1)*peo,i*peo-1); 63 } 64 if(new_sum>k) 65 { 66 break; 67 } 68 } 69 cout<<zu<<endl; 70 } 71 return 0; 72 }