1 条题解
-
0
自动搬运
来自洛谷,原作者为

HoshiuZ
生命潦草,我在弯腰。搬运于
2025-08-24 21:49:43,当前版本为作者最后更新于2020-02-24 11:27:46,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
设是定义在整数集合上的二院函数。若对于定义域上的任意整数,其中,都有成立,则称函数满足四边形不等式。
定理
设是定义在整数集合上的二元函数。若对于定义域上的任意整数,其中,都有成立,则函数满足四边形不等式。
证明
对于,有
对于,有
两式相加,得到
以此类推,对于任意的,有
同理,对任意的,有
决策单调性
在状转方程中,若函数满足四边形不等式,则具有决策单调性。
证明
定义表示的最优决策点。
,根据为的最优决策点,则有
,因为满足四边形不等式,则有
移项,可得
与第一个不等式相加,可得
即的最优决策点一定大于等于。故具有决策单调性。
应用
那么知道其有决策单调性后,有什么应用呢?
既然其有决策单调性,定义表示的最优决策点,则内一定是非严格单调递增的。
那么根据此性质,满足决策单调性的题目主要有两种处理手法。
方法一:单调队列
可以用单调队列维护决策集合。
当求出一个新的时,考虑可以作为哪些的最优决策。根据决策单调性,我们一定可以找到一个位置,在该位置之前,内存储的决策都比要优,其后都比差。于是便可以将该位置及其后面的部分全部变为,即此时它们的最优决策均为。
一个位置一个位置的修改效率很低,所以可以建立一个队列,代替。队列中保存三个量,表示~的值都是。
对于每个,执行以下操作:
-
检查队头:设队头为,若,则删除队头(因为队头不需要了,之前的值已经被求出)。否则则令。
-
取队头保存的最优决策进行状态转移,计算出。
-
尝试插入新决策,步骤如下
(1) 取出队尾,即为
(2) 若对于来说,是比更优的决策,即,记,删除队尾,返回步骤(1)。
(3) 若对于来说,是比更优的决策,即,去往步骤(5)。
(4) 否则,则在上二分查找出位置,在此之前决策比优,在此之后决策更优,将修改为,去往步骤(5)。
(5) 把三元组插入队尾。
时间复杂度。
方法二:分治
假设已知的最优决策在上。
定义,设的最优决策为,根据决策单调性,可知的最优决策在内,的最优决策在内。
于是将问题分割成了同类型的规模更小的问题,便可递归分治。
时间复杂度
例题 [POI2011]Lightning Conductor
给定一个长度为的序列,对于每个,求出一个最小的非负整数,使得 ,都有。
数据范围
,。
链接
思路
而为非负整数,则
$$p=\lceil \max\{ a_j+\sqrt{|i-j|}\}\rceil-a_i,\forall j\in[1,n] $$那么问题便转变为求$\lceil \max\{ a_j+\sqrt{|i-j|}\}\rceil,\forall j\in[1,n]$。
可以考虑做两次,正做一次,将序列翻转再做一次,结果取两次的最大值,这样便可以去掉绝对值
$$\lceil \max\{ a_j+\sqrt{i-j}\}\rceil,\forall j\in[1,i) $$定义。
此处的即为。
定义。
则
$$w(a,c+1)+w(a+1,c)-[w(a,c)+w(a+1,c+1)]=\sqrt{c-a-1}+\sqrt{c-a+1}-2\sqrt{c-a} $$令,原式变为
$$\sqrt{d-1}+\sqrt{d+1}-2\sqrt{d}=(\sqrt{d+1}-\sqrt{d})-(\sqrt{d}-\sqrt{d-1}) $$而函数单调递减
则该式恒小于。
即。
可推广到对于,。
可以发现,这东西与四边形不等式的符号相反。将上面的证明过程符号取反(因为本题求的是),便可证明满足决策单调性。
于是采用上面两种方法实现即可。
由于函数较慢,且本题反复调用,可提前预处理出~。
代码(单调队列)
#include<bits/stdc++.h> #define N 500010 using namespace std; int n,head,tail,a[N]; double dp[N],sqr[N]; struct node{ int l,r,p; }q[N]; double w(int j,int i) { return double(a[j])+sqr[i-j]; } int binary_search(int t,int x) { int ans=q[t].r+1,l=q[t].l,r=q[t].r; while(l<=r) { int mid=l+r>>1; if(w(q[t].p,mid)<=w(x,mid)) ans=mid,r=mid-1; else l=mid+1; } return ans; } void insert(int i) { q[tail].l=max(q[tail].l,i); while(head<=tail&&w(i,q[tail].l)>=w(q[tail].p,q[tail].l)) tail--; if(head>tail) { q[++tail].l=i; q[tail].r=n; q[tail].p=i; } else { int pos=binary_search(tail,i); if(pos>n) return ; q[tail].r=pos-1; q[++tail].l=pos; q[tail].r=n; q[tail].p=i; } } void work() { head=1,tail=0; for(int i=1;i<=n;i++) { insert(i); if(head<=tail&&q[head].r<i) head++; else q[head].l=i; dp[i]=max(dp[i],w(q[head].p,i)); } } int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; sqr[i]=sqrt(i); } work(); for(int i=1;i<=n/2;i++) swap(a[i],a[n-i+1]),swap(dp[i],dp[n-i+1]); work(); for(int i=n;i>=1;i--) cout<<(int)ceil(dp[i])-a[i]<<endl; return 0; }代码(分治)
#include<bits/stdc++.h> #define N 500010 using namespace std; int n,a[N]; double dp[N],sqr[N]; double w(int j,int i) { return double(a[j])+sqr[i-j]; } void work(int l,int r,int L,int R) { if(l>r) return ; int mid=l+r>>1,p; double maxn=0; for(int i=L;i<=min(mid,R);i++) { if(w(i,mid)>maxn) maxn=w(i,mid),p=i; } dp[mid]=max(dp[mid],maxn); work(l,mid-1,L,p); work(mid+1,r,p,R); } int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; sqr[i]=sqrt(i); } work(1,n,1,n); for(int i=1;i<=n/2;i++) swap(a[i],a[n-i+1]),swap(dp[i],dp[n-i+1]); work(1,n,1,n); for(int i=n;i>=1;i--) cout<<(int)ceil(dp[i])-a[i]<<endl; return 0; }参考资料
《算法竞赛进阶指南》
-
- 1
信息
- ID
- 2591
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者