题面:
思路:
题意有点绕,实际上就是给你一个计算规则,让你取最少的元素,通过这个计算方式,得到一个小于指定误差上限的结果
这个规则分为三个部分,这里分别用pre,sum,suf表示
因为给定的元素个数(天数)很少,可以使用O(n^3)算法,因此考虑使用经过了预处理的dp解决问题
具体地,设dp[i][j]表示前i个元素使用了j个且一定取用了第i个时可能达到的最小误差值
预处理:pre[i]表示通过第一种计算方式得到的,第一个元素取第i个时得到的误差
suf[i]同理,为第三种计算方式
sum[i][j]则表示取了i和j且不取中间的元素时,中间的元素产生的误差
这样dp[i][1]=pre[i],dp[i][j]=dp[k][j-1]+sum[k][i](k=1...i-1),然后用dp[i][j]+suf[j]更新答案即可
Code:
1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<cstdio> 5 #include<algorithm> 6 #define inf 0x7fffffff/2 7 using namespace std; 8 int n,m,a[110]; 9 int dp[110][110]; 10 //dp[i][j]: prefix 1-i,chosen j 11 int pre[110],suf[110],sum[110][110]; 12 int abs(int k){ 13 if(k>=0) return k; 14 else return -k; 15 } 16 int main(){ 17 freopen("baric.in","r",stdin); 18 freopen("baric.out","w",stdout); 19 int i,j,k,tmp1,tmp2,t,l; 20 scanf("%d%d",&n,&m); 21 int ans=m,anss=n; 22 for(i=1;i<=n;i++){ 23 scanf("%d",&a[i]); 24 dp[i][1]=0; 25 } 26 for(i=1;i<=n-2;i++){ 27 for(j=i+2;j<=n;j++){ 28 for(k=i+1;k<j;k++){ 29 sum[i][j]+=abs((a[k]<<1)-a[i]-a[j]); 30 } 31 } 32 } 33 for(i=1;i<=n;i++){ 34 for(j=1;j<i;j++) pre[i]+=abs(a[i]-a[j])<<1; 35 dp[i][1]=pre[i]; 36 for(j=n;j>i;j--) suf[i]+=abs(a[i]-a[j])<<1; 37 } 38 for(i=2;i<=n;i++){ 39 for(j=2;j<=i;j++){ 40 dp[i][j]=inf/2; 41 for(k=1;k<i;k++) dp[i][j]=min(dp[i][j],dp[k][j-1]+sum[k][i]); 42 if(dp[i][j]+suf[i]<m){ 43 if(j<ans) ans=j,anss=dp[i][j]+suf[i]; 44 else if(j==ans&&dp[i][j]+suf[i]<anss) anss=dp[i][j]+suf[i]; 45 } 46 } 47 } 48 printf("%d %d",ans,anss); 49 }