1. 程式人生 > >【BZOJ4953】lydsy七月月賽 F DP

【BZOJ4953】lydsy七月月賽 F DP

clu include memset int ems target print return ++

【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;
}

【BZOJ4953】lydsy七月月賽 F DP