一般的式子都是 $f_i = max\{g_j + w_{(i,j)}\}$

然后这个 $w$ 满足决策单调性,也就是对于任意 $i < j$ ,$best_i \leq best_j$

这样就会有两种优化方式

1.$w_{(i,j)}$ 可以快速求

例如:NOI 2009 诗人小 G

题里给了你 $L,P$ 和单调递增的 $s$ 数组,然后 $f_i = min \{ f_j + |s_i-s_j-L-1|^P \} \space (j < i)$

可以发现以一个点为最优决策的点是一段区间

我们可以用单调栈维护这个区间,具体地,在栈里存一个三元组 $(l,r,x)$ 表示 $[l,r]$ 的最优决策都在 $x$

一开始栈里只有一个区间 $(1,n,0)$,考虑对每次加入的 $i$,更新这个栈

1) 如果 $i$ 可以转移到当前的区间 $[l,r]$,且 $i$ 比 $x$ 优,我们发现 $i$ 完爆 $x$ ,没理由留着 $x$

2) 不管 $i$ 有没有完爆 $x$,因为决策单调性,$i$ 可以影响后面一段区间($i$ 从左到右,所以当前的 $i$ 显然在 $x$ 右边,有可能成为后面某段区间的最优决策),我们在 $[min(L,i+1),R]$ 这段区间上二分找出一个位置 $p$ 满足 $p$ 以前 $x$ 最优,$p$ 及以后 $i$ 最优,把 $(p,n,i)$ 加入队列,并把 $(l,r,x)$ 改成 $(l,p-1,x)$(如果不存在 $p$ 就不加)

所以从左到右每次加入一个 $i$ ,更新它的 $f$ 数组,然后把它的贡献加入栈里就可以了

复杂度 $O(nlogn)$

#include<bits/stdc++.h>
#define LL long long
#define DB long double
using namespace std;
inline int read()
{
int x = ,f = ;char ch = getchar();
for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
for(;isdigit(ch);ch = getchar())x = * x + ch - '';
return x * f;
}
const int maxn = ,maxw = ;
int n,l,p;
char s[maxn][maxw];
DB f[maxn];
int sum[maxn],top;
struct Deci
{
int l,r,x;
Deci(){}
Deci(int _l,int _r,int _x){l = _l,r = _r,x = _x;}
}st[maxn];
inline DB calc(int j,int i)
{
DB res = 1.0,cur = 1.0 * abs((sum[i] + i - sum[j] - j - ) - l);
for(int i=;i<=p;i++)res *= cur;
return res;
}
int main()
{
int T = read();
while(T--)
{
n = read(),l = read(),p = read();
int cur = ;
for(int i=;i<=n;i++)
{
scanf("%s",s[i] + );
sum[i] = sum[i - ] + strlen(s[i] + );
}
st[top = ] = Deci(,n,);
for(int i=;i<=n;i++)
{
f[i] = f[st[cur].x] + calc(st[cur].x,i);
while(st[top].l > i && f[i] + calc(i,st[top].l) < f[st[top].x] + calc(st[top].x,st[top].l))top--;
int L = max(i + ,st[top].l),R = st[top].r,ans;
while(L <= R)
{
int mid = (L + R) >> ;
if(f[i] + calc(i,mid) < f[st[top].x] + calc(st[top].x,mid))R = mid - ;
else L = mid + ;
}
st[top].r = L - ;
if(L <= n)st[++top] = Deci(L,n,i);
if(st[cur].r == i)cur++;
}
if(f[n] > 1e18)puts("Too hard to arrange");
else printf("%lld\n",(LL)f[n]);
puts("--------------------");
}
}

2.$w_{(i,j)}$ 不能快速求

例如:Lydsy1712 月赛 Problem D. 小 Q 的书架

把一个数列分成 $k$ 段,最小化 $\sum$ 每一段内的逆序对

$n \leq 40000,k \leq 10$

先吐槽,这个数据范围给我,我绝对不去莫队

区间逆序对好像不是很可算,只能莫队,但这个莫队还是动态查询,所以复杂度非常没有保障

然后 $w_{(i,j)}$ 虽然满足四边形不等式,但复杂度不是很对

可以分治,每次对于一个区间 $[l,r]$ 假设它的最优决策在 $[ql,qr]$ 上

令 mid=(l+r)>>1 ,我们可以暴力扫 $[l,mid]$ 找出它的最优决策点 $x$,然后递归解决 $[l,mid-1],[ql,x]$ 和 $[mid+1,r],[x,qr]$ 这两个子问题

这样做是 $O(nlogn)$ 的,复杂度证明同归并排序

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
int x = ,f = ;char ch = getchar();
for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
for(;isdigit(ch);ch = getchar())x = * x + ch - '';
return x * f;
}
const int maxn = ;
int n,k;
int c[maxn],a[maxn],f[maxn],g[maxn];
inline int lowbit(int x){return x & (-x);}
inline void add(int x,int v){for(;x <= n;x += lowbit(x))c[x] += v;}
inline int cal(int x){int res = ;for(;x;x -= lowbit(x))res += c[x];return res;}
int nl,nr,ans;
inline void Get(int l,int r)
{
while(nl > l)nl--,ans += cal(a[nl] - ),add(a[nl],);
while(nr < r)nr++,ans += cal(n) - cal(a[nr]),add(a[nr],);
while(nl < l)add(a[nl],-),ans -= cal(a[nl] - ),nl++;
while(nr > r)add(a[nr],-),ans -= cal(n) - cal(a[nr]),nr--;
}
void solve(int l,int r,int L,int R)
{
if(l > r)return;
int mid = (l + r) >> ,x;
for(int i=min(mid,R+);i>L;i--)
{
Get(i,mid);
if(g[i - ] + ans < f[mid])f[mid] = g[i - ] + ans,x = i - ;
}
solve(l,mid - ,L,x);solve(mid + ,r,x,R);
}
int main()
{
n = nr = read();nl = ;
k = read();
for(int i=;i<=n;i++)
{
a[i] = read();
f[i] = f[i - ] + cal(n) - cal(a[i]);
add(a[i],);
}ans = f[n];
for(int i=;i<=k;i++)
{
for(int i=;i<=n;i++)g[i] = f[i],f[i] = 1e9;
solve(,n,,n - );
}
cout<<f[n]<<endl;
}

[基本操作]决策单调性优化dp的更多相关文章

  1. Lightning Conductor 洛谷P3515 决策单调性优化DP

    遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...

  2. CF868F Yet Another Minimization Problem 分治决策单调性优化DP

    题意: 给定一个序列,你要将其分为k段,总的代价为每段的权值之和,求最小代价. 定义一段序列的权值为$\sum_{i = 1}^{n}{\binom{cnt_{i}}{2}}$,其中$cnt_{i}$ ...

  3. 2018.09.28 bzoj1563: [NOI2009]诗人小G(决策单调性优化dp)

    传送门 决策单调性优化dp板子题. 感觉队列的写法比栈好写. 所谓决策单调性优化就是每次状态转移的决策都是在向前单调递增的. 所以我们用一个记录三元组(l,r,id)(l,r,id)(l,r,id)的 ...

  4. [BZOJ4850][JSOI2016]灯塔(分块/决策单调性优化DP)

    第一种方法是决策单调性优化DP. 决策单调性是指,设i>j,若在某个位置x(x>i)上,决策i比决策j优,那么在x以后的位置上i都一定比j优. 根号函数是一个典型的具有决策单调性的函数,由 ...

  5. BZOJ2216 Poi2011 Lightning Conductor 【决策单调性优化DP】

    Description 已知一个长度为n的序列a1,a2,...,an. 对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt( ...

  6. 决策单调性优化dp 专题练习

    决策单调性优化dp 专题练习 优化方法总结 一.斜率优化 对于形如 \(dp[i]=dp[j]+(i-j)*(i-j)\)类型的转移方程,维护一个上凸包或者下凸包,找到切点快速求解 技法: 1.单调队 ...

  7. BZOJ4899: 记忆的轮廓【概率期望DP】【决策单调性优化DP】

    Description 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增, 在[1,n]中,一共有n个节点.我 ...

  8. 2018.10.14 NOIP训练 猜数游戏(决策单调性优化dp)

    传送门 一道神奇的dp题. 这题的决策单调性优化跟普通的不同. 首先发现这道题只跟r−lr-lr−l有关. 然后定义状态f[i][j]f[i][j]f[i][j]表示猜范围为[L,L+i−1][L,L ...

  9. 洛谷 P5897 - [IOI2013]wombats(决策单调性优化 dp+线段树分块)

    题面传送门 首先注意到这次行数与列数不同阶,列数只有 \(200\),而行数高达 \(5000\),因此可以考虑以行为下标建线段树,线段树上每个区间 \([l,r]\) 开一个 \(200\times ...

随机推荐

  1. Pacemaker详解

    一.前言 云计算与集群系统密不可分,作为分布式计算和集群计算的集大成者,云计算的基础设施必须通过集群进行管理控制,而作为拥有大量资源与节点的集群,必须具备一个强大的集群资源管理器(Cluster sy ...

  2. LVM逻辑磁盘管理

    一.简介 LVM是逻辑盘卷管理(Logical Volume Manager)的简称,它是Linux环境下对磁盘分区进行管理的一种机制,LVM是建立在硬盘和分区之上的一个逻辑层,来提高磁盘分区管理的灵 ...

  3. 计算机网络概述 传输层 TCP流量控制

    TCP流量控制 所谓流量控制就是让发送发送速率不要过快,让接收方来得及接收.利用滑动窗口机制就可以实施流量控制.通过运用TCP报文段中的窗口大小字段来控制,发送方的发送窗口不可以大于接收方发回的窗口大 ...

  4. 网络:W5500 UDP数据包格式注意事项

     1. 主题 使用W5500测试UDP功能,发现收到的数据包和wireshark抓包的数据不同. 原来W5500接收寄存器的数据包并不是网络上的数据流,而是经过内部处理后展现出来的. 对于这个问题目前 ...

  5. Struts2笔记01——基础MVC架构(转)

    原始内容:https://www.tutorialspoint.com/struts_2/basic_mvc_architecture.htm Apache Struts 2是用来创建企业级Java ...

  6. python中类(class)和实例(instance)

    面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 ...

  7. MySQL-重做日志 redo log -原理

    [redo log buffer][redo log file]-原理 目录: 1.重做日志写入过程图 2.相关知识点汇总图 3.redo_log_buffer 原理 4.redo_log_file ...

  8. 【转载】有向图强连通分量的Tarjan算法

    转载地址:https://www.byvoid.com/blog/scc-tarjan [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly conn ...

  9. tcp三次握手过程

    TCP握手协议 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接.第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确 ...

  10. Struts2 hibernate spring 概念总结

    Hibernate工作原理及为什么要用? 原理:1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件2.由hibernate.cfg.x ...