BZOJ 4953: [Wf2017]Posterize

题目在这里呀~

题意

有256个位置,有n个位置上有人,你可以在至多k个位置上插旗,每个人都会走到离自己最近的旗子,求所有人走的距离的平方和的最小值。

题解

嗯听说这题难在题意??这是WF2017最简单的一道题qwq
一看就是dp吧。 f i , j 表示前i个位置插了j面旗,且第i位置上必须插旗的最小代价。那么转移 f i , j = m i n ( f p , j 1 + w p , 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;
}

猜你喜欢

转载自blog.csdn.net/leo_nasir/article/details/81144325