Description
数字图像的像素可以用三个在0到255之间的整数表示,它们分别表示红色、绿色和蓝色的强度。为了压缩图片或是为了产生艺术效果,许多图像编辑工具收录了如下所述的”色调分离”操作。每个颜色通道会分别考虑,本题只考虑红色通道的情况。不同于在红色通道使用0到255之间全部的整数,一张色调分离后的图片只会使用这些数字里至多 k 种整数。每个像素原来的红色强度会被替换成最相近的可用强度。图像编辑工具会选择k个整数来最小化替换过程引起的平方误差之和。假设原图有n个像素,它们的红色取值是r1,···,rn,而 k 种可用整数为v1,···,vk ,那么平方误差之和被定义为
你的任务是计算可以实现的最小平方误差之和,参数k和图片的红色强度会给出。
题解:
区间DP。 f[i][j] 表示到第i种颜色,用了j种数字的最小代价,状态转移见代码。注意一下算 cost[i][j] (从i到j用一种数字的最小代价)时,若直接暴力,复杂度为 O(n2) ,会TLE,预处理几个前缀和,则可以 O(n) 求出。总时间复杂度为 O(n3) 。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=270;
int d,k;
LL r[maxn],p[maxn],f[maxn][maxn],s1[maxn],s2[maxn],s3[maxn];
LL work(LL x,LL y)
{
LL ans=(1LL<<62);
for(LL i=0;i<256;i++)
ans=min(ans,i*(s1[y]-s1[x-1])+i*i*(s3[y]-s3[x-1]));
return ans+s2[y]-s2[x-1];
}
int main()
{
memset(f,63,sizeof(f));
scanf("%d%d",&d,&k);
s1[0]=s2[0]=s3[0]=f[0][0]=0;
for(int i=1;i<=d;i++)
{
scanf("%lld%lld",&r[i],&p[i]);f[0][i]=0;
s1[i]=s1[i-1]-2*p[i]*r[i];
s2[i]=s2[i-1]+p[i]*r[i]*r[i];
s3[i]=s3[i-1]+p[i];
}
for(int i=1;i<=d;i++)
f[i][1]=work(1,i);
for(int i=1;i<=d;i++)
for(int j=1;j<=i;j++)
{
LL cost=work(j,i);
for(int l=2;l<=k;l++)
f[i][l]=min(f[i][l],f[j-1][l-1]+cost);
}
LL ans=f[d][0];
for(int i=1;i<=k;i++)ans=min(ans,f[d][i]);
printf("%lld",ans);
}