牵扯到一些数论技巧,如果每转移一次状态计算一次方差是很不方便的。
设最终每段xi个字母,最终的方差
s=1/k( (x1-av)^2+(x2-av)^2+...(xk-av)^2)
对于总数一定的全部字母,分成k段,每段平均值av是定值,又因为k也是定值,所以我们dp[i][j]直接代表前i个单词分成j段时,“ ( (x1-av)^2+(x2-av)^2+...(xk-av)^2 ”这一部分的最小和即可。
对于一个i,j向前推若干个表示第j行算进去的单词,由dp[t][j-1]转移而来即可。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <memory>
#include <queue>
# include<math.h>
# include<iomanip>
# include<map>
# define mod 10007
# include<math.h>
# include<stack>
using namespace std;
typedef long long int ll;
typedef double dl;
dl sum[1010];
dl len[1010];
dl dp[1010][110];
int main()
{
int n,k;
cin>>n>>k;
getchar();
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
len[i]=s.length();
sum[i]=sum[i-1]+len[i];
}
dl av=sum[n]/k;
fill(dp[0],dp[0]+1010*110,0x7fffffff);
for(int i=1;i<=n;i++)
{
dp[i][1]=(sum[i]-av)*(sum[i]-av);
for(int j=2;j<=k;j++)
{
for(int t=1;t<i;t++)
{
dp[i][j]=min(dp[i][j],dp[t][j-1]+(sum[i]-sum[t]-av)*(sum[i]-sum[t]-av));
}
}
}
cout<<fixed<<setprecision(1)<<dp[n][k]/k;
return 0;
}