CSU 1364 Interview RMQ

题意:

  瑶瑶有一家有一家公司,最近他想招m个人。因为他的公司是如此的出名,所以有n个人来参加面试。然而,瑶瑶是如此忙,以至于没有时间来亲自面试他们。所以他准备选择m场面试来测试他们。

  瑶瑶决定这样来安排面试。首先,他把这些面试者按照来到的顺序排成一队。然后,他把这个队列切成m段。每段的长度是[n/m](向下取整),这意味着他将忽略掉剩下的人。然后,他将选择每一段里面最好的那个人。

  瑶瑶的想法看起来很有趣,但是他遇到了另外的问题。他把每个人的能力赋了一个值。值越大的越好。他希望员工足够的好,这样,他们的和可以达到他的目标k(严格大于)。另一方面,因为现在高昂的工资,他希望员工的数量尽可能少。

  你能帮他找出最小的m吗?

思路:

  Sparse Table + 枚举区间长度。

  枚举区间个数会TLE,不懂为什么,代码也有点没看懂。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <cmath>
 5 
 6 using namespace std;
 7 
 8 const int MAXN = (int)2e5+5;
 9 
10 int ST[21][MAXN]; //Sparse Table
11 int hight[MAXN];
12 int n, k;
13 
14 inline int topBit(int x) {
15     return (int) (log((double)x)/log(2.0));
16 }
17 
18 inline int Query(int L, int R) {
19     int h = hight[R-L];
20     if ((R-L) < (1<<h)) h -= 1;
21     return max(ST[h][L], ST[h][R-(1<<h)]);
22 }
23 
24 int main() {
25     #ifdef Phantom01
26         freopen("CSU1364.in", "r", stdin);
27     #endif // Phantom01
28 
29     memset(hight, 0, sizeof(hight));
30     for (int i = 1; i < MAXN; i++) //比他左位移一位的数高一
31         hight[i] = hight[i>>1] + 1;
32 
33     while (scanf("%d %d", &n, &k)!=EOF) {
34         if (-1==n && -1==k) break;
35 
36         for (int i = 0; i < n; i++)
37             scanf("%d", &ST[0][i]); //最下面一层就是原始数据
38 
39         int h = hight[n];
40         for (int i = 1; i <= h; i++) {
41             for (int j = 0; j < n; j++) {
42                 if ((j+(1<<(i-1))) < n)
43                     ST[i][j] = max(ST[i-1][j], ST[i-1][j+(1<<(i-1))]);
44                 else
45                     ST[i][j] = ST[i-1][j];
46             }
47         }
48         int ans = -1;
49         for (int i = n; i > 0; i--) {
50             int m = n/i;
51             int tmp = 0;
52             for (int j = 0; j < m; j++) {
53                 tmp += Query(j*i, (j+1)*i);
54                 if (tmp>k) {
55                     ans = j+1; //不知道这里为啥是j+1而不是 m
56                     break;
57                 }
58             }
59             if (tmp > k)
60                 break;
61         }
62         printf("%d
", ans);
63     }
64 
65     return 0;
66 }
View Code

 -------------------------

PS: 后来看到一个代码,直接二分答案即可,复杂度也是n*log(n)的,但是编程复杂度没这么大。

 1 #include <cstdio>
 2  
 3 int a[200010], n;
 4  
 5 bool Can(int m, int k)
 6 {
 7     int i, j, t, sum, MAX;
 8     t = n / m;
 9     for (i = j = sum= 0; i < m; i++)
10     {
11         MAX = -1;
12         for (j = 0; j < t; j++)
13             if (MAX < a[i*t+j]) MAX = a[i*t+j];
14         sum += MAX;
15         if (sum > k) return true;
16     }
17     return sum > k;
18 }
19  
20 int main()
21 {
22     int k, m, up, down, i, sum;
23     //freopen("in", "r", stdin);
24     while (scanf("%d%d", &n, &k), n >= 0 && k >= 0)
25     {
26         for (i = sum = 0; i < n; i++)
27         {
28             scanf("%d", a + i);
29             sum += a[i];
30         }
31         if (sum <= k) puts("-1");
32         else {
33             down = 1; up = n;
34             while (down < up)
35             {
36                 m = (up + down) / 2;
37                 if (Can(m, k)) up = m;
38                 else down = m + 1;
39             }
40             printf("%d
", up);
41         }
42     }
43     return 0;
44 }
View Code
原文地址:https://www.cnblogs.com/Phantom01/p/3657819.html