您的位置:首页 > 其它

2012-2013 ACM-ICPC, Asia Tokyo Regional Contest Beautiful Spacing 二分 + dp + 双指针扫描

2017-09-13 20:21 656 查看
题意 : 给你一个含n个单词的文本,按照一些规则放入宽度为w的矩形中,怎样使最大的空格最小。

题解 : 首先我们可以发现答案是满足二分性质的,如果少的空格可以那么多的也一定可以,这样的话我们就可以对答案进行二分,判断一个mid 是否可以成为答案。我们定义dp[i]表示第i个单词能不能当某一行的末尾,这样的话,我们可以定义dp[0] = 1 认为一开始的满足的 (这就是边界条件),dp[i] 肯定是从前面一个1的位置转移过来的,但是直接暴力前面的1的位置的话最坏情况是 n
^ 2 logn的 肯定超时,这个时候我们发现所有的可能解都在一个小区间 (l,r) 内这样我们就可以用双指针扫描这个小区间就可以了。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int res[maxn] = {0};
ll len[maxn] = {0};
int dp[maxn] = {0};
ll pre[maxn] = {0};
int cnt = 0;
ll n,m;
ll mid;
ll i;
ll ans = 1000000007;
bool check (ll k) {
ll mi = pre[i] - pre[k] + i - k - 1ll;
ll mx = pre[i] - pre[k] + (i - k - 1ll) * mid;
if (mi <= m && mx >= m) return true;
return false;
}
int main () {
ios_base :: sync_with_stdio(false);
while(cin >> m >> n && n) {
memset (pre,0,sizeof (pre));
for (i = 1;i <= n ; ++ i) {
cin >> len[i];
pre[i] = pre[i - 1] + len[i];
}
int r = m;
int l = 1;
while (r >= l) {
mid = (l + r) >> 1;
memset (dp,0,sizeof (dp));
dp[0] = 1;
cnt = 1;
int start = 0;
int end = 0;
for (i = 1;i <= n; ++ i) {
while (((i - res[end] - 1ll) * mid) + pre[i] - pre[res[end]] > m && end < cnt - 1) {
end ++;
}
for (int j = end;j >= start; -- j) {
if (((i - res[j] - 1) + pre[i] - pre[res[j]]) > m) {
start = j + 1;
break;
}
dp[i] = check(res[j]);
if (dp[i]) {
res[cnt ++] = i;
start = j;
break;
}
}
}
for (i = n;i >= 0;-- i) {
if (dp[i]) {
if ((pre
- pre[i] + n - i - 1) <= m) {
ans = min (ans,mid);
r = mid - 1;
}
else {
l = mid + 1;
}
break;
}
}
}
cout << ans << endl;
ans = 100000007;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp codeforces
相关文章推荐