题意:
瑶瑶有一家有一家公司,最近他想招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 }
-------------------------
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 }