首页 > 其他分享 >重修 斜率优化 Dp

重修 斜率优化 Dp

时间:2022-08-15 22:01:08浏览次数:58  
标签:min 2s 重修 斜率 tail Dp 单调 define

斜率单调暴力移指针

斜率不单调二分找答案

\(x\) 坐标单调开单调队列

\(x\) 坐标不单调开平衡树 / cdq分治

P4072 [SDOI2016]征途

我们要求方差最小,而总和不变,等价于要每天走的路程平方和最小。

设 \(s(i)\) 表示前 \(i\) 段路的距离总和。

首先我们有一个 naive 的 \(O(n^3)\) DP:

设 \(f(i,j)\) 表示走完前 \(n\) 段,用了 \(j\) 天的最小平方和。

\[f(i,j)=\min_{k=0}^i f(k,j-1)+(s(i)-s(k))^2 \]

发现后面的 \((s(i)-s(k))^2\) 明显就是斜率优化 DP,我们转化一下形式:

\[\begin{aligned} f_j(i)&=\min_{k=0}^i f_{j-1}(k)+s^2(i)+s^2(k)-2s(i)s(k) \\&=s^2(i)+\min_{k=0}^i f_{j-1}(k)+s^2(k)-2s(i)s(k) \end{aligned} \]

若转移至 \(f_j(i)\) 时 \(k_0\) 不比 \(k\) 劣,则有

\[f_{j-1}(k_0)+s(k_0)^2-2s(i)s(k_0)\le f_{j-1}(k)+s^2(k)-2s(i)s(k) \]

将 \(i\) 有关移到一侧:

\[\frac{(f_{j-1}(k_0)+s(k_0)^2)-(f_{j-1}(k)+s^2(k))}{s(k_0)-s(k)}\le 2s(i) \]

不妨设 \(g(k)=f_{j-1}(k)+s^2(k)\),则

\[\frac{g(k_0)-g(k)}{s(k_0)-s(k)}\le 2s(i) \]

发现左边就是 \((s(k_0),g(k_0)),(s(k),g(k))\) 两点间的斜率。

所以说,我们对于每一次 \(j-1\to j\),都进行斜率优化,复杂度 \(O(n^2)\)。

(\(x\) 坐标单调开单调队列)

点击查看代码
//We'll be counting stars.
//#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define fir first
#define sec second
#define mkp make_pair
#define pb emplace_back
#define For(i,j,k) for(int i=(j),i##_=(k);i<=i##_;i++)
#define Rof(i,j,k) for(int i=(j),i##_=(k);i>=i##_;i--)
#define ckmx(a,b) a=max(a,b)
#define ckmn(a,b) a=min(a,b)
#define debug(...) cerr<<"#"<<__LINE__<<": "<<__VA_ARGS__<<endl
#define int long long
#define db double
#define N 3003 
int n,m,a[N],f[2][N],q[N],head,tail;
inline int pw(int x){ return x*x; }
db SL(bool o,int x,int y){//slope
	return 1.*((f[o][y]+pw(a[y]))-(f[o][x]+pw(a[x])))/(a[y]-a[x]);
}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);
	cin>>n>>m;
	For(i,1,n) cin>>a[i];
	For(i,2,n) a[i]+=a[i-1];
	For(i,1,n) f[1][i]=pw(a[i]);
	bool o;
	int tmp;
	For(i,2,m){
		o=(i&1)^1;
		head=1,tail=0;
		For(j,1,n){
			while(head<tail && SL(o,q[head],q[head+1])<2*a[j])
				head++;
			tmp=q[head];
			f[o^1][j]=f[o][tmp]+pw(a[j]-a[tmp]);
			while(head<tail && SL(o,q[tail-1],q[tail])>=SL(o,q[tail],j))
				tail--;
			q[++tail]=j;
		}
	}
	tmp=f[m&1][n];
	cout<<m*tmp-pw(a[n]);
return 0;}

标签:min,2s,重修,斜率,tail,Dp,单调,define
From: https://www.cnblogs.com/shaojia/p/16589805.html

相关文章

  • 洛谷P2622 关灯问题II引发的关于DP实现形式及后效性的思考
      动态规划要求已经求解的子问题不受后续阶段的影响,即无后效性。而在这种递推的实现方式中,后面枚举的状态可能更新前面已经枚举过的状态。也就是说,这种递推的实现方式是......
  • ubuntu dpkg问题解决
    问题今天玩ubuntu发现以下报错:dpkgwasinterrupted,youmustmanuallyrunsudodpkg–configure-atocorrecttheproblem 解决sudorm/var/lib/apt/lists/l......
  • TCP和UDP的应用场景
    传输层的两个协议,TCP(TransmissionControlProtocol,传输控制协议)和UDP(UserDatagramProtocol,用户数据报协议),有各自的应用场景。TCP应用场景TCP为应用层协议提供可靠传输......
  • TCP/UDP学习笔记
    TCP/UDP学习笔记相同点:1.都工作在传输层2.都在程序之间传输数据(二进制文件),可以是文件、视频、图片等不同点:TCP:面向连接(握手挥手)、完整可靠(丢包重发)、顺序(序列传输)......
  • 数位DP-902. 最大为 N 的数字组合
    问题描述给定一个按 非递减顺序 排列的数字数组 digits 。你可以用任意次数 digits[i] 来写的数字。例如,如果 digits=['1','3','5'],我们可以写数字,如 '13', '5......
  • P5131 荷取融合——计数dp,组合计数
    本题是一个计数类的问题,其中需要有一些优化。简单思路从题面和数据范围,可以猜测算法时间复杂度大概是\(O(nk)\),所以不难想到用动态规划:设\(f(i,j)\)为前\(i\)个数中选\(......
  • 数位DP-1012. 至少有 1 位重复的数字
    问题描述给定正整数 n,返回在 [1,n] 范围内具有至少1位重复数字的正整数的个数。示例1:输入:n=20输出:1解释:具有至少1位重复数字的正数(<=20)只有11。示......
  • 【luogu CF1710C】XOR Triangle(数位DP)
    XORTriangle题目链接:luoguCF1710C题目大意给你一个数n,要你求有多少个满足条件的a,b,c使得它们两两异或得到的三个值可以得到一个非退化三角形。其中a,b,c值域在......
  • 周回顾并发编程与数据库08.14:UDP协议、操作系统发展史、相关名词、进程、线程、验证py
    目录UDP协议操作系统发展史相关名词进程线程锁信号量event事件池协程数据库MySQLSQL与NoSQL内容UDP协议Internet协议集支持一个无连接的传输协议,该协议......
  • 树形dp
    ##1.换根dp1.kamp首先肯定它是换根dp因为最后一次不用回到起点,所以先不去想别的,最后再减去一个最长链设g\([i],\)为以i为根前往在这颗子树中的家的最小距离\(f[i],\)......