[LUOGU] P4767 [IOI2000]邮局

https://www.luogu.org/problemnew/show/P4767

四边形不等式好题!

可以设f[i][j]表示前i个村庄,建了j个邮局的最小代价。

转移:f[i][j]=min{f[k][j-1]+dis[k+1][i]}

也就是枚举断点,断点后整个区间建造一个邮局并强制整个区间都选择它。

这个邮局在哪里最优呢?由人类智慧知,在中位数处最优。

注意到这样的转移下,时间复杂度是O(m*n^2)的,不行

这是一个前缀问题,但是同时它也是一个区间问题,回忆四边形不等式的形式,尝试套上去

至此,我们就有了O(nm)的优秀做法。

(证明暂时不会,有会证明的欢迎留言..)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

inline int rd(){
  int ret=0,f=1;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret*f;
}

const int MAXN=3005;

int n,m;
int val[MAXN],sum[MAXN],dis[MAXN][MAXN];
int f[MAXN][305],tran[MAXN][305];

int main(){
  memset(f,0x3f,sizeof(f));
  n=rd();m=rd();
  for(int i=1;i<=n;i++) val[i]=rd();
  sort(val+1,val+1+n);
  for(int i=1;i<=n;i++) sum[i]=sum[i-1]+val[i];
  for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)
      dis[i][j]=dis[i][j-1]+val[j]-val[i+j>>1];
  for(int i=1;i<=n;i++) f[i][1]=dis[1][i];
  int mn=1<<30,mnid;
  for(int j=2;j<=m;j++){
    tran[n+1][j]=n-1;
    for(int i=n;i>=j;i--){
      for(int k=tran[i][j-1];k<=tran[i+1][j];k++){
        if(f[k][j-1]+dis[k+1][i]<f[i][j]){
          f[i][j]=f[k][j-1]+dis[k+1][i];
          tran[i][j]=k;
        }
      }
    }
  }
  cout<<f[n][m];
  return 0;
}

本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9347976.html

原文地址:https://www.cnblogs.com/ghostcai/p/9347976.html