zoukankan      html  css  js  c++  java
  • est


    【问题描述】
    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 }
  • 相关阅读:
    POJ 1703 Find them, Catch them
    POJ 2236 Wireless Network
    POJ 2010 Moo University
    POJ 2184 Cow Exhibition
    POJ 3280 Cheapest Palindrome
    POJ 3009 Curling 2.0
    POJ 3669 Meteor Shower
    POJ 2718 Smallest Difference
    POJ 3187 Backward Digit Sums
    POJ 3050 Hopscotch
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/4725249.html
Copyright © 2011-2022 走看看