题意:每行限制宽度为m,然后给出n个单词的长度,将它们排版,每行不得超过m。最后对于每一行,如果不满m,则会有(m-len)^2的惩罚,求最小惩罚。(每两个单词之间会有一个空格,每行最后一个单词没有空格)

题解:dp[i]代表将前i个单词排好所花费的代价,sum[i]代表前i个单词的总长度,那么dp[i]=min(dp[j]+(m-(sum[i]-sum[j]+i-j-1))),j<i且满足sum[i]-sum[j]+i-j-1<=m,由于m<=100,所以nm的复杂度还是可以接受的。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const long long inf=1ll<<62;
 6 typedef long long LL;
 7 LL dp[10005];
 8 LL sum[10005],a[10005];
 9 inline LL cal(LL x)
10 {
11     return x*x;
12 }
13 int main()
14 {
15     int T;
16     for(scanf("%d",&T);T;T--)
17     {
18         LL n,m;
19         scanf("%lld%lld",&m,&n);
20         dp[0]=sum[0]=0;
21         for(int i=1;i<=n;i++)
22         {
23             scanf("%lld",&a[i]);
24             sum[i]=sum[i-1]+a[i];
25         }
26         for(int i=1;i<=n;i++)
27         {
28             LL val=inf;
29             for(int j=i-1;j>=0;j--)
30             {
31                 if(sum[i]-sum[j]+i-j-1<=m)
32                     val=min(val,dp[j]+cal(m-sum[i]+sum[j]-i+j+1));
33                 else
34                     break;
35             }
36             dp[i]=val;
37         }
38         printf("%lld\n",dp[n]);
39     }
40     return 0;
41 }