CDQパーティションは、スロープの最適化を設定し、

CDQパーティションは、スロープの最適化を設定し、

いくつかの特別なダイナミックプログラミングの問題があり、一見に変えること\(\ FRAC {F_J-F_K } {g_j-g_k} <K_I \) 勾配不等式が、実際には、\(K_I \)\(G_J \)\(G_k \)ではなく単調、それが単調キュー/スタック実装バイナリサーチ単調なスロープ最適化することはできません。このように、巨大な男がCDQパーティションは最適化のスロープを設定します思い付いがあるでしょう。

どのようにCDQ?

サブ状態に応じて\(K \)小から大に、パーティション、再帰前に、元の状態に応じて、シーケンスインデックスが変更されないままソートの内部順序前に、2つのサブサブシーケンス、シーケンスに分割されます。

する長さの再帰的配列(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]);
}

おすすめ

転載: www.cnblogs.com/OIER-Yu/p/11440027.html