题意
有256个位置,有n个位置上有人,你可以在至多k个位置上插旗,每个人都会走到离自己最近的旗子,求所有人走的距离的平方和的最小值。
题解
嗯听说这题难在题意??这是WF2017最简单的一道题qwq
一看就是dp吧。
fi,j
f
i
,
j
表示前i个位置插了j面旗,且第i位置上必须插旗的最小代价。那么转移
fi,j=min(fp,j−1+wp,i)
f
i
,
j
=
m
i
n
(
f
p
,
j
−
1
+
w
p
,
i
)
wp,i
w
p
,
i
表示p到i之间只有p位置和i位置都插旗,p到i之间的人所要走的最小距离。可以通过预处理得到,怎么预处理应该不用说吧,就是往p和i近的那个走。
//Suplex
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define N 256
#define ll long long
using namespace std;
const ll inf=1e18;
int d,k,a[N+10];
ll w[N+10][N+10],f[N+10][N+10],ans;
inline ll min(ll a,ll b)
{
if(a<b) return a;
return b;
}
int main()
{
scanf("%d%d",&d,&k);
if(k>=d){puts("0");return 0;}
for(int i=1;i<=d;i++){
int x;
scanf("%d",&x);
scanf("%d",&a[x+1]);
}
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++){
for(int p=i+1;p<j;p++)
if(j-p<=p-i) w[i][j]+=(ll)(j-p)*(j-p)*a[p];
else w[i][j]+=(ll)(p-i)*(p-i)*a[p];
}
for(int i=1;i<=N;i++)
for(int j=1;j<i;j++) f[i][1]+=(ll)(i-j)*(i-j)*a[j];
for(int i=2;i<=N;i++)
for(int j=2;j<=min(k,i);j++){
f[i][j]=inf;
for(int p=j-1;p<i;p++) f[i][j]=min(f[p][j-1]+w[p][i],f[i][j]);
}
ans=f[N][k];
for(int i=N-1;i>=k;i--){
ll res=0;
for(int j=N;j>i;j--) res+=(ll)(j-i)*(j-i)*a[j];
ans=min(ans,f[i][k]+res);
}
printf("%lld\n",ans);
return 0;
}