P3648 [APIO2014] 序列分割
对于这道题,我们很容易想出一个暴力 DP
:
设
我们可以得到一个式子:
显然,这个式子的复杂度是
这么大的差距,我们肯定得去找个性质来优化。(明显只有找到性质才能逼近正解)
我们考虑区间
所以说,从上面的式子来看,我们其实并不需要关心将块分开的顺序,只需要关心从哪些位置分开。
因此,我们便可以将状态简化为:设
我们可以发现,这个式子满足
写成斜率优化的式子:
因为是求
最后输出方案只需要每次将决策点记下即可。
代码要过的话,细节有点多,需要好好调。
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int NN = 2e5 + 8; int n,k; int j; ll a[NN],s[NN]; ll f[NN]; ll h[NN]; ll g[NN][208]; ll ans[NN]; int que[NN],head,tail; inline double Slope(int x,int y){if(s[x] == s[y]) return 1e-18;return ((h[x] - s[x] * s[x])-(h[y] - s[y] * s[y])) / (double)(s[x]-s[y]);} int main(){ // freopen("1.in","r",stdin); scanf("%lld%lld",&n,&k); for(int i = 1; i <= n; ++i) scanf("%lld",&a[i]),s[i] = s[i-1] + a[i]; for(j = 1; j <= k; ++j){ head = 1;tail = 0; que[++tail] = 0; for(int i = 1; i <= n; ++i) h[i] = f[i]; for(register int i = 1; i <= n; ++i){ while(head < tail && Slope(que[head],que[head+1]) >= -s[i]) ++head; int k = que[head]; g[i][j] = k; f[i] = h[k] + s[k] * (s[i] - s[k]); while(head < tail && Slope(que[tail],que[tail-1]) <= Slope(que[tail],i)) --tail; que[++tail] = i; } } printf("%lld\n",f[n]); int now = n,pos = 1; for(int i = k; i >= 1; --i){ now = ans[i] = g[now][i]; if(now == 0) {pos = i+1;break;} } for(int i = pos; i <= k; ++i) printf("%lld ",ans[i]); }
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/solution_P3648.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步