首页 > 技术文章 > est

CXCXCXC 2015-08-12 18:28 原文


【问题描述】
BG 是一个著名的诗人,经常作诗自娱自乐。但是,他一直被一件事情所困扰,那就是
诗的排版问题。
一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在同一行
中, 注意一行中可以放的句子数目是没有限制的。 BG 给每首诗定义了一个行标准长度 M (行
的长度为一行中符号的总个数) ,他希望排版后每行的长度都和前一行相差不远,且不能超
过行标准长度。显然排版时,不应改变原有的句子顺序,并且 BG 不允许把一个句子分在两
行或者更多的行内。在满足上面两个条件的情况下,BG 对于排版中的每行定义了一个不协
调度,为这行的实际长度与前一行实际长度的差值绝对值(第一行为 0) 。一个排版的不协
调度为所有行不协调度的总和。
TYZ 最近作了几首诗,现在他想让 BG 对作品润色。当然他希望能尽可能取悦 BG, 所
以请你对这些诗进行排版,使得排版后的不协调度最小
【输入格式】
第一行两个整数 M,N。M 代表行标准长度,N 代表有 N 个句子
第二行给出 N 个数,代表着 N 个句子格子的长度。
【输出格式】
输出仅一行,表示最小不协调度
【样例输入】
6 4
4 3 2 5
【样例输出】
3
【数据范围】
30% N<=100
100% N<=2000
1<=M,sigma(Ai)<=1e9
题目保证有解

  F[i,j]表示前j个单词,最后一行是[i,j]的最小代价。

  F[i,j]=min{F[k,i-1]+|S[i,j]-S[k,i-1]|}

  将绝对值拆开

  1) s[i][j]>=s[k][i-1],此时随着j的增加,k的取值范围不断向左移(减小)[k,i-1]  

  2) s[i][j]<s[k][i-1],此时随着j的减小,k的取值范围不断向右移(增加)[1,k]

  直接前后缀维护最大值即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int inf=1e9;
 4 int M,N,ans;
 5 int f[2010][2010],s[2010][2010];
 6 int a[2010];
 7 int main(){
 8     freopen("est.in","r",stdin);
 9     freopen("est.out","w",stdout);
10 
11     scanf("%d%d",&M,&N);
12     for (int i=1;i<=N;i++)
13         scanf("%d",&a[i]);
14     
15     for (int i=1;i<=N;i++)
16         for (int j=i;j<=N;j++)
17             s[i][j]=s[i][j-1]+a[j]+(j!=i);//前缀和 + 空格 
18     
19     for(int i=0;i<=2009;i++){
20         for(int j=0;j<=2009;j++)
21             f[i][j]=inf;
22     }
23     for (int i=1;i<=N;i++)
24         if (s[1][i]<=M)
25             f[1][i]=0;
26     
27     for (int i=2;i<=N;i++){
28         int k=i;
29         int Min=inf;
30         //s[i][j]>=s[k][i-1],此时随着j的增加,k的取值范围不断向左移(增加)[k,i-1]    
31         for(int j=i;j<=N;j++){// i ~ j为当前行的诗句 
32             if (s[i][j]<=M){
33                 while (k>1&&s[k-1][i-1]<=s[i][j]){
34                     k--;
35                     Min=min(Min,f[k][i-1]-s[k][i-1]);
36                 }
37                 f[i][j]=Min+s[i][j];
38             }
39         }
40         
41         //s[i][j]<s[k][i-1],此时随着j的减小,k的取值范围不断向右移(减小)[1,k]
42         //直接前后缀维护最大值即可。
43         k=1;Min=inf;
44         for (int j=N;j;j--){ 
45             if (s[i][j]<=M){
46                 while (k<=i&&s[i][j]<=s[k][i-1]){
47                     Min=min(Min,f[k][i-1]+s[k][i-1]);
48                     k++;
49                 }
50                 f[i][j]=min(f[i][j],Min-s[i][j]);
51             }
52         }
53     }
54     ans=inf;
55     for (int i=1;i<=N;i++)
56         ans=min(ans,f[i][N]);
57     printf("%d",ans);
58     
59     return 0;
60 }

 

推荐阅读