CDQ分治套斜率优化
Posted oier-yu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CDQ分治套斜率优化相关的知识,希望对你有一定的参考价值。
CDQ分治套斜率优化
有一些特殊的动态规划题目,貌似可以化作\(\fracf_j-f_kg_j-g_k<K_i\)的斜率不等式,但实际上,\(K_i\)和\(g_j\)以及\(g_k\)却没有单调性,所以无法用单调队列/二分搜索单调栈实现斜率优化。于是,便有巨佬便想出了CDQ分治套斜率优化的方法。
如何CDQ?
对子状态按照\(K\)从小到大排序,分治,递归前,将子序列按照子状态的原下标分成两个子序列,子序列内部保持之前排序的顺序不变;
递归到子序列长度为\(1\)时,像普通斜率优化一样建点;
回溯时,将左子序列中的状态插入单调队列,像普通斜率优化一样对右子序列中的状态更新。
这样的话,当递归到底层时,当前子状态已经被所有原下标在自己之前的状态更新了。
例题: [SDOI2012]任务安排
代码实现:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#define int long long
#define maxn 300000
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
void read(int &x)
int f=1;x=0;char ch=getchar();
while(!isdigit(ch))if(ch=='-') f=-1;ch=getchar();
while(isdigit(ch))x=x*10+ch-'0';ch=getchar();
x*=f;
int A[maxn+5],B[maxn+5],F[maxn+5];
struct vec
int i,x,y;vec()i=x=y=0;
vec(int x,int y)i=0,this->x=x,this->y=y;
vec(int i,int x,int y)this->i=i,this->x=x,this->y=y;
friend vec operator-(vec a,vec b)return vec(a.x-b.x,a.y-b.y);
friend bool operator<(vec a,vec b)if(a.x==0) return 0;return 1.0*a.y/a.x<1.0*b.y/b.x;
s[maxn+5],q[maxn+5],t[maxn+5];
int head=1,tail=0;
void push(vec x)
while(tail>head&&(x-q[tail-1])<(q[tail]-q[tail-1])) tail--;
q[++tail]=x;
void pop(int k)
while(tail>head&&(q[head+1]-q[head])<vec(1,k)) head++;
int n,ss;
void CDQ(int left,int right)
if(left==right)s[left].x=B[left],s[left].y=F[left];return;
int mid=(left+right)/2,x1=left-1,x2=mid;
for(int i=left;i<=right;i++)
s[i].i<=mid?t[++x1]=s[i]:t[++x2]=s[i];
for(int i=left;i<=right;i++) s[i]=t[i];
CDQ(left,mid),head=1,tail=0;
for(int i=left;i<=mid;i++) push(s[i]);
for(int i=mid+1;i<=right;i++)
pop(ss+A[s[i].i]);
int j=q[head].i;
F[s[i].i]=min(F[s[i].i],F[j]+ss*(B[n]-B[j])+A[s[i].i]*(B[s[i].i]-B[j]));
CDQ(mid+1,right),x1=left,x2=mid+1;
for(int i=left;i<=right;i++)
if(x1<=mid&&(x2>right||s[x1].x<s[x2].x||(s[x1].x==s[x2].x&&s[x1].y<s[x2].y))) t[i]=s[x1++];
else t[i]=s[x2++];
for(int i=left;i<=right;i++) s[i]=t[i];
bool cmp(vec a,vec b)return A[a.i]<A[b.i];
#undef int
int main()
#define int long long
read(n),read(ss);
for(int i=1;i<=n;i++) read(A[i]),read(B[i]),A[i]+=A[i-1],B[i]+=B[i-1],s[i].i=i;
memset(F,0x3f,sizeof(F));
F[0]=0,sort(s+1,s+n+1,cmp);
CDQ(0,n);
printf("%lld\n",F[n]);
以上是关于CDQ分治套斜率优化的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)
bzoj3963[WF2011]MachineWorks cdq分治+斜率优化dp
BZOJ3963[WF2011]MachineWorks cdq分治+斜率优化
[BZOJ1492][NOI2007]货币兑换Cash(斜率优化+CDQ分治)