P17210 【模板】半在线决策单调性 题解
Zskioaert1106 · · 题解
题目传送门:P17210 【模板】半在线决策单调性
前置知识:决策单调性
对于 DP 最优化转移,若
若对于
常见的一种决策单调性的充分条件是四边形不等式,可以用反证法证明。
四边形不等式:若对
a \leqslant b \leqslant c \leqslant d ,总有w(a,c)+w(b,d) \leqslant w(a,d)+w(b,c) (交叉小于包含),则称函数w 满足四边形不等式。
:::info[证明]
不妨记
假设存在
此外,存在两种限制性质。
-
称
w 支持移动访问,如果w(j,i) 可以从w(j \pm 1,i) 或w(j,i \pm 1) 以O(1) 时间得到。 -
称
w 需要动态计算,如果w(j,i) 依赖于\{f_{j'}:j'<j\} ,即f 和w 只能顺次计算。
如果
若
前置知识:简化 LARSCH 算法
当求解
-
-
仅考虑
[1,l) 内的决策点时,r 的最优决策点p'_r 。
记
-
遍历区间
[p_{l-1},p'_r] ,更新mid 的最优决策点p'_{mid} 。可以证明只考虑[1,l) 内的决策点时仍有p_l=p'_l \leqslant p'_{mid} \leqslant p'_r ; -
递归求解
[l,mid] ; -
遍历区间
[l,mid] ,更新决策点p'_r ; -
递归求解
(mid,r] 。
那么如何证明第一步遍历区间
若
当
证明考虑左右指针的移动次数,每层可以视为跑一个来回。
:::info[证明]
对于
对于
对于
对于
题目分析
状态
接着我们要证明其决策单调性。
:::info[
分别考虑每个元素
由此摆上这个简化 LARSCH 算法,初始化每个
代码实现
#include<iostream>
using namespace std;
constexpr int N=500005;
int n,a[N],b[N],p[N];
long long f[N];
struct pointer{
int l=1,r,cnt[N];
long long sum;
void move(int L,int R){
while(L<l)sum+=cnt[a[--l]]++;
while(r<R)sum+=cnt[a[++r]]++;
while(l<L)sum-=--cnt[a[l++]];
while(R<r)sum-=--cnt[a[r--]];
}
}t1,t2;
void solve(int l,int r){
if(l==r)return;
int mid=l+r>>1;
for(int i=p[l-1];i<=p[r];i++){
t1.move(i+1,mid);
long long w=f[i]+b[mid]+t1.sum;
if(w<f[mid])f[mid]=w,p[mid]=i;
}
solve(l,mid);
for(int i=l;i<=mid;i++){
t2.move(i+1,r);
long long w=f[i]+b[r]+t2.sum;
if(w<f[r])f[r]=w,p[r]=i;
}
solve(mid+1,r);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=1;i<=n;i++){
t1.move(1,i);
f[i]=b[i]+t1.sum;
}
solve(1,n);
for(int i=1;i<=n;i++)cout<<f[i]<<' ';
return 0;
}
AC 记录。