摘樱桃
【题目描述】
有n个樱桃排成一列,第i个樱桃的甜度为v[i],你要把n个樱桃分成若干组,其中每一组的樱桃必须相邻。每一组樱桃的美味度为(sum-T)^2 , 其中sum是这组樱桃的甜度之和,T为输入给定的系数。
一组方案的美味度为每一组的美味度之和。
求可行方案最小的美味度。
【输入格式】
输入文件cherry.in
第一行两个正整数 n,T。
第二行n个整数,第i个整数是第i个樱桃的甜度,v[i]。
【输出格式】
输出文件cherry.out
一行一个非负整数,为最小美味度。
【样例输入】
5 5
3 5 2 1 6
【样例输出】
【数据范围】
对于50%的数据满足 n<=10,T<=1000,v[i]<=10
对于70%的数据满足 n<=100
对于所有数据,n<=10^3,T<=1000,v[i]<=10
每组樱桃必须相邻,使美味度之和最小。很容易联想到其实和石子合并差不多,可以用区间划分来做。但是看一眼数据1000,n3的复杂度,应该会tle(事实证明就是会T了)。
那么应该怎么样优化呢,我们可以考虑,不采用区间划分,我们枚举有多少个樱桃,然后再枚举这个樱桃和最后几个樱桃组成一组。
具体实现的话,我们要整一个前缀和(求甜度要用),我们可以用f【i】表示前i个樱桃的最少甜度那么,用j来枚举与第i个樱桃组成一组的樱桃的数量的开始,那么状态转移方程就出来了
f[i]=min(f[i],f[j]+(sum[i]-sum[j-1]-t)*(sum[i]-sum[j-1]-t));
最后附上代码
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 int n,a[1010],f[1010],t,sum[1010]; 6 int main() 7 { 8 scanf("%d%d",&n,&t); 9 memset(f,0x3f,sizeof(f)); 10 for(int i=1;i<=n;++i) 11 { 12 scanf("%d",&a[i]); 13 sum[i]=sum[i-1]+a[i]; 14 } 15 16 f[1]=(a[1]-t )*(a[1]-t); 17 f[0]=0; 18 for(int i=2;i<=n;++i) 19 { 20 for(int j=i-1;j>=0;--j) 21 { 22 f[i]=min(f[i],f[j]+(sum[i]-sum[j]-t)*(sum[i]-sum[j]-t)); 23 } 24 } 25 printf("%d",f[n]); 26 return 0; 27 }