POJ1160 [IOI2000]邮局 [四边形不等式优化dp]
题目描述见链接 .
设 表示前 个村庄, 建立 个邮局的最优值,
: ,
其中 表示在 放置一个邮局, 管辖 的村庄的最小值, 显然放在 中位数 位置最优,现在考虑如何 计算 ,
设 表示 的距离前缀和, 表示 的距离后缀和, 可以 预处理 .
设 为 的中位数所在村庄编号,
则
然后经过 打表 可知, 满足四边形不等式:
同时与此对应的最优决策 也 满足决策单调性: .
于是可以使用 四边形不等式 优化 ,
先给出 打表/暴力 程序
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
const int maxn = 3005;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
int N;
int K;
int A[maxn];
int p[maxn][maxn];
ll sl[maxn];
ll sr[maxn];
ll sum_l[maxn];
ll sum_r[maxn];
ll F[maxn][maxn];
ll w[maxn][maxn];
int main(){
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
N = read(); K = read();
for(reg int i = 1; i <= N; i ++) A[i] = read();
std::sort(A+1, A+N+1);
for(reg int i = 1; i <= N; i ++) sum_l[i] = sum_l[i-1] + A[i], sl[i] = sum_l[i] + sl[i-1];
for(reg int i = N; i >= 1; i --) sum_r[i] = sum_r[i+1] + A[i], sr[i] = sum_r[i] + sr[i+1];
for(reg int i = 1; i <= N; i ++)
for(reg int j = i; j <= N; j ++){
int m = i+j >> 1;
w[i][j] = (1ll*m-i)*A[m] - (sum_l[m-1] - sum_l[i-1]) + (sum_r[m+1] - sum_r[j+1]) - (1ll*j-m)*A[m];
}
memset(F, 0x3f, sizeof F); F[0][0] = 0;
for(reg int i = 1; i <= N; i ++)
for(reg int j = 1; j <= i; j ++){
for(reg int k = 0; k < i; k ++){
ll t = F[k][j-1] + w[k+1][i];
if(t < F[i][j]){
F[i][j] = t;
p[i][j] = k;
}
}
}
for(reg int i = 1; i <= N; i ++)
for(reg int j = 1; j <= i; j ++)
if(i!=N && j != 1 && (p[i][j-1] > p[i][j] || p[i][j] > p[i+1][j])){
printf("False\n");
}else if(i != N && j != i && (F[i+1][j+1] + F[i][j] > F[i+1][j] + F[i][j+1])){
printf("False\n");
}
printf("%lld\n", F[N][K]);
return 0;
}
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define reg register
typedef long long ll;
const int maxn = 3005;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
int N;
int K;
int A[maxn];
int p[maxn][305];
ll sum_l[maxn];
ll sum_r[maxn];
ll F[maxn][305];
ll w[maxn][maxn];
int main(){
N = read(); K = read();
for(reg int i = 1; i <= N; i ++) A[i] = read();
std::sort(A+1, A+N+1);
for(reg int i = 1; i <= N; i ++) sum_l[i] = sum_l[i-1] + A[i];
for(reg int i = N; i >= 1; i --) sum_r[i] = sum_r[i+1] + A[i];
for(reg int i = 1; i <= N; i ++)
for(reg int j = i; j <= N; j ++){
int m = i+j >> 1;
w[i][j] = (1ll*m-i)*A[m] - (sum_l[m-1] - sum_l[i-1]) + (sum_r[m+1] - sum_r[j+1]) - (1ll*j-m)*A[m];
}
memset(F, 0x3f, sizeof F); F[0][0] = 0;
for(reg int j = 1; j <= K; j ++){
p[N+1][j] = N-1;
for(reg int i = N; i >= 1; i --)
for(reg int k = p[i][j-1]; k <= p[i+1][j]; k ++){
ll t = F[k][j-1] + w[k+1][i];
if(t < F[i][j]) F[i][j] = t, p[i][j] = k;
}
}
printf("%lld\n", F[N][K]);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)