【BZOJ4953】lydsy七月月赛 F
题解:设f[i][j]表示第i个强度取为j时的最小误差。那么每次转移时,我们只计算j‘和j之间的像素点带来的误差,于是有:
$f[i][j]=min(f[i-1][k]+g(k..mid,k)+g(mid+1...j,j))|mid={k+j\over 2}$
其中,&g(a,b)=P_a*(a-b)^2\\=P_a*a*a-2*P_a*a*b+2*P_a*b*b&
于是维护P_a*a*a,P_a*a,P_a的前缀和即可。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; ll s0[300],s1[300],s2,f[300][300],ans; int n,m; int main() { scanf("%d%d",&n,&m); int i,j,k,mid; for(i=1;i<=n;i++) scanf("%d",&j),scanf("%lld",&s0[j]),s1[j]=j*s0[j],s2+=j*j*s0[j]; for(i=1;i<=255;i++) s0[i]+=s0[i-1],s1[i]+=s1[i-1]; memset(f,0x3f,sizeof(f)); ans=1ll<<60; for(i=1;i<=m;i++) { if(i==1) for(j=0;j<=255;j++) f[1][j]=s0[j]*j*j-2*s1[j]*j; else for(j=i-1;j<=255;j++) { for(k=i-2;k<j;k++) { mid=j+k>>1; f[i][j]=min(f[i][j],f[i-1][k]+(s0[mid]-s0[k])*k*k+(s0[j]-s0[mid])*j*j-2*(s1[mid]-s1[k])*k-2*(s1[j]-s1[mid])*j); } } if(i==m) for(j=i-1;j<=255;j++) f[i][j]+=(s0[255]-s0[j])*j*j-2*(s1[255]-s1[j])*j,ans=min(ans,f[i][j]); } printf("%lld",ans+s2); return 0; }
时间: 2024-10-15 06:09:03