Description
排版是很有讲究的。假设稿纸的宽度是W个字符,长度不限,当你对一篇文章排版时,必须满足以下条件:
1.必须保持单词的次序。下图显示了对4个单词“This is a pen”在一张宽11字符的稿纸上排版的结果:

Input
输入的第一行是用空格分隔的两个正整数W和N(3<=W<=80000,2<=N<=50000),分别代表稿纸的宽度和单词数。接下来有N个正整数,第i个正整数xi代表第i个单词的长度(1<=xi<=(W-1)/2)。
Output
输出一个整数,代表最美观的排版中,最多出现多少个连续空格。
Sample Input
输入1:
11 4
4 2 1 3
输入2:
5 7
1 1 1 2 2 1 2
输入3:
11 7
3 1 3 1 3 3 4
输入4:
100 3
30 30 39
输入5:
30 3
2 5 3
Sample Output
输出1:
2
输出2:
1
输出3:
2
输出4:
40
输出5:
1
Data Constraint
2<=N<=50000
.
.
.
.
.
.
分析
第一眼就是二分(然而理解错题意把自己给推翻了)
先二分出空格的长度,再去检验
设f[i]表示能否以第i个单词为行末
那么显然f[i]可以由多个f[j]转移而来,即钦定j+1~i为一行
那么理论上j的上界为i-2,下界为一个使a[i]-a[j]+i-j-1<=w的,最小的j (bz)。
当某行单词数量减少时,空格数目会迅速增加
即若不考虑f[j]本身,那么j直接取bz就是最佳的选择。
.
.
.
.
.
程序:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int w,n;
bool f[50010];
long long a[50010];
bool check(int x)
{
int bz=-1,j=0;
memset(f,false,sizeof(f));
f[0]=1;
for (int i=1;i<=n-1;i++)
{
while (j<i&&a[i]-a[j]+((long long)x*(i-j-1))>=w)
{
if (f[j]==true) bz=j;
j++;
}
if (a[i]-a[bz]+(i-bz-1)<=w&&bz!=-1) f[i]=true; else f[i]=false;
}
for (int i=n-1;i>=0;i--)
if (f[i]==true&&a[n]-a[i]+(n-i-1)<=w) return true;
return false;
}
int main()
{
scanf("%d%d",&w,&n);
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[i]=a[i-1]+x;
}
int l=1,r=w-2,ans;
while (l<=r)
{
int mid=(l+r)/2;
if (check(mid)==true)
{
ans=mid;
r=mid-1;
} else l=mid+1;
}
printf("%d",ans);
return 0;
}

本文深入探讨了一种针对文章排版的算法,旨在找到在限定宽度的稿纸上排版时,能够达到最美观效果的排版方案。通过二分搜索确定连续空格的最大数量,确保单词顺序不变的同时,优化排版的视觉效果。
3万+

被折叠的 条评论
为什么被折叠?



