决策单调性
判断决策单调性可以选择打表,有个比较好用的判断是这样的。
dpdpdp 转移式:f(i)=minj<i{f(j)+calc(j,i)}f(i)=\min_{j<i}\{ f(j)+calc(j,i)\}f(i)=minj<i{f(j)+calc(j,i)}
如果任意 a<ba<ba<b 满足 calc(a,b+1)+calc(a+1,b)≤calc(a,b)+calc(a+1,b+1)calc(a,b+1)+calc(a+1,b)\le calc(a,b)+calc(a+1,b+1)calc(a,b+1)+calc(a+1,b)≤calc(a,b)+calc(a+1,b+1) ,则 f(i)f(i)f(i) 具有决策单调性。
决策单调性优化 dpdpdp
-
分治做法
处理 solve(l,r,ql,qr)solve(l,r,q_l,q_r)solve(l,r,ql,qr) ,意思是 qlq_lql ~ qrq_rqr 的决策点在 lll ~ rrr 之中,现在要分治求 qlq_lql ~ qrq_rqr 的决策点。
mid=ql+q22mid=\frac{q_l+q_2}{2}mid=2ql+q2 ,遍历 lll ~ rrr 求出 midmidmid 的决策点 ppp 。
递归处理 solve(l,p,ql,mid−1)solve(l,p,q_l,mid-1)solve(l,p,ql,mid−1) , solve(l,p,mid+1,qr)solve(l,p,mid+1,q_r)solve(l,p,mid+1,qr) 。
缺点:有些情况只是遍历 lll ~ rrr 难求出 midmidmid 的决策点,这时候要 cdqcdqcdq 分治里面套决这个分治 ,见例题。
-
单调栈做法
(我今天之前只会这种做法2333
用单调栈维护若干个单元三元组 (p,l,r)(p,l,r)(p,l,r) 表示 lll ~ rrr 的决策点为 ppp 。
刚开始单调栈为空。
每求出一个 f(x)f(x)f(x) ,就更新单调栈中的三元组,具体:从栈中取出一个三原组 (p,l,r)(p,l,r)(p,l,r) 然后 checkcheckcheck f(l)f(l)f(l) 从 xxx 转移过来更优还是 ppp 转移过来更优。如果 xxx 更优,就把这个三元组删除。否则就在 lll ~ rrr 中二分出一个点 l′l'l′ 满足从 xxx 转移过来更优。最后把 (x,l′,n)(x,l',n)(x,l′,n) 加入单调栈。
PSPSPS :为什么可以这么做就不赘述了,其实挺显然的。
gym 102904B Dispatch Money
分治套分治做法+逆序对
#include <bits/stdc++.h>
#define N 300005
using namespace std;
typedef long long ll;
const ll inf=1e17;
int n,co,a[N],x=1,y,t[N];
ll ans[N],cnt;
int sum(int pos){ int res=0; for(;pos;pos-=pos&-pos) res+=t[pos]; return res; }
void add(int pos,int c){ for(;pos<=n;pos+=pos&-pos) t[pos]+=c; }
ll ask(int l,int r){
while(x>l) cnt+=sum(a[x-1]), add(a[x-1],1), --x;
while(y<r) cnt+=y-x+1-sum(a[y+1]), add(a[y+1],1), ++y;
while(x<l) add(a[x],-1), cnt-=sum(a[x]), ++x;
while(y>r) add(a[y],-1), cnt-=y-x-sum(a[y]), --y;
return cnt;
}
void solve(int l,int r,int ql,int qr){
if(ql>qr)return;
int mid=(ql+qr)>>1,v=0; ll now,m=inf;
for(int i=l;i<=r&&i<mid;i++)
if((now=(ans[i]+ask(i+1,mid)))<m) m=now,v=i; ans[mid]=min(m+co,ans[mid]);
solve(l,v,ql,mid-1),solve(v,r,mid+1,qr);
}
void cdq(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
cdq(l,mid);
solve(l,mid,mid+1,r);
cdq(mid+1,r);
}
int main(){
cin>>n>>co;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),ans[i]=inf;
cdq(0,n);
cout<<ans[n]<<endl;
}
本文探讨了决策单调性的判断与优化方法,重点介绍了分治策略在处理决策点问题上的应用,以及单调栈技巧在维护决策点上的高效性。通过实例Gym102904BDispatchMoney展示了如何结合分治套分治和逆序对技术解决复杂问题。
1430

被折叠的 条评论
为什么被折叠?



