Beautiful Spacing
题意:
文本每行有w列,有n个单词。排列规则如下:
1、每两个单词之间必须有空格
2、除了最后一行,每行第一个单词第一个字母必须顶格,最后一个单词最后一个字母必须在最后一格。
3、同一个单词不能换行
要使得最大间隔最小
解决:
使最大值最小的问题,显然二分。
验证的时候不能像一般题目贪心验证。
dp[i]为第i个单词做开头的时候,对于待验证值x,枚举可行结尾j,则每个可行结尾j对应了下一个可行开头 j + 1,这样一来状态转移就出来了,朴素的dp中n^2的复杂度被减枝很多。再者,如果 [i, j]这一段中,每两个的单词之间空位都是x,且仍不能填满一行,则[i+1, j]一定也不能达到填满一行的要求。所以这个时候,对于每个可行开头i, 枚举可行结尾的时候,不用再从i+1开始。
1 #include <bits/stdc++.h> 2 3 const int MAXN = 50000+10; 4 5 int w, n; 6 int a[MAXN]; 7 int s[MAXN]; 8 bool dp[MAXN]; 9 10 bool check(int x) 11 { 12 // printf("check(%d) ", x); 13 memset(dp, false, sizeof(dp)); 14 dp[1] = true; 15 if (s[n] + n - 1 <= w) 16 return true; 17 for (int l = 1, t = 2; l <= n; ++l) { 18 if (dp[l] == true) { 19 for (int r = std::max(l+1, t); r <= n; ++r) { 20 int cnt = r - l + 1; 21 int len = s[r] - s[l-1]; 22 int max_len = (cnt-1)*x + len; 23 int min_len = cnt - 1 + len; 24 // printf("l = %d, r = %d, min_len = %d, max_len = %d ", l, r, min_len, max_len); 25 if (min_len > w) 26 break; 27 if (max_len < w) 28 continue; 29 dp[r + 1] = true; 30 // printf("r = %d ", r); 31 t = r+1; 32 if (s[n] - s[r] + n - r <= w) { 33 return true; 34 } 35 } 36 } 37 } 38 // printf("false!! "); 39 return false; 40 41 } 42 43 int main() 44 { 45 46 while (~scanf("%d%d", &w, &n)) { 47 if (w == 0 && n == 0) 48 break; 49 s[0] = 0; 50 for (int i= 1; i <= n; ++i) 51 scanf("%d", a+i), s[i] = s[i-1] + a[i]; 52 if (s[n] + n-1 <= w) { 53 printf("%d ", 1); 54 continue; 55 } 56 int l = 1, r = w; 57 while (l <= r) { 58 int mid = l + r >> 1; 59 if (check(mid)) { 60 r = mid - 1; 61 } 62 else 63 l = mid + 1; 64 } 65 printf("%d ", l); 66 } 67 return 0; 68 }