斜率DP十连测

[模板] 斜率优化Dp详解 算法简介今天xinyue讲了斜率优化,全程懵逼,居然还有这么牛逼的东西。 于是与achen讨论了一下,总结一些东西。 斜率优化Dp其实是单调队列的推广,单调队列、旋转卡壳、斜率优化都利用了单调性降低时间复杂度。算法简介举个例子 有些动规状态转移方程可以写成 f[i]=min/max{f[j]+…+x[i]},省略号中只有与j有关的变量。 我们就可以用单调队列进行优化,使O(n^2)降为O( 阅读详情


最近学校里很多题目都没时间做,顺便来写一下博客
斜率DP十连:

A[征途]

注意到,原题的式子,等价于 m∑a2i−(∑ai)2 m ∑ a i 2 − ( ∑ a i ) 2 后面部分是常数
那么我们就可以写出dp方程 f[i,j]=min{f[i−1,k]+(sj−sk)2},k<j f [ i , j ] = m i n { f [ i − 1 , k ] + ( s j − s k ) 2 } , k < j
对每个i单独做斜率dp,那么式子改写为 fi=min{−2sjsi+fj+s2j+s2i} f i = m i n { − 2 s j s i + f j + s j 2 + s i 2 }
斜率为 si s i ,维护下凸包即可

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long 
using namespace std;
int n,m,q[3010],T; LL f[2][3010],s[3010];
inline LL y(int j){
    return f[T^1][j]+s[j]*s[j];
}
inline db slp(int j,int k){
    return (y(j)-y(k))/(db)(2.*(s[j]-s[k])); 
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%lld",s+i),s[i]+=s[i-1];
    for(int i=1;i<=m;++i){
        int l=0,r=0; T=i&1;
        for(int j=1;j<=n;++j){
            while(l<r && slp(q[l],q[l+1])<s[j]) ++l; int k=q[l];
            f[T][j]=y(k)+s[j]*s[j]-2*s[j]*s[k]; 
            while(l<r && slp(q[r-1],q[r])>slp(q[r],j)) --r;
            q[++r]=j;
        }
    }
    printf("%lld\n",m*f[m&1][n]-s[n]*s[n]);
}




B[货币兑换]

是一个神仙题也
首先注意到一个贪心策略,每天要么全部买入,全部卖出或者什么也不做
好的,注意到这一点之后就可以考虑怎么dp了,设 fi f i 表示到了第i天最多有多少钱
xi x i 表示到了第i天最多有多少a股, yi y i 表示同时最多有多少b股
我们有三种转移
1.今天什么也不做 fi=fi−1 f i = f i − 1
2.今天卖掉从某一天买来的股票 fi=max{ai∗xj+bi∗yj},j<i f i = m a x { a i ∗ x j + b i ∗ y j } , j < i
3.买入股票 yi=fiai∗ratei+bi,xi=yi∗ratei y i = f i a i ∗ r a t e i + b i , x i = y i ∗ r a t e i
重点关注第二条式子,我们将其改写:

yj=−aibi∗xj+fibi y j = − a i b i ∗ x j + f i b i

这里b是常数可以不管,只需要维护上凸包,让后在凸包上二分斜率 −aibi − a i b i 即可
但是发现 −aibi − a i b i 不是单调的,我们需要选择以下一项:
1.splay维护凸包
2.cdq分治
前者明显比后者直观易懂,所以我们用splay维护凸包,过程和用队列差不多,只是如果一个点被加入到了凸包内部需要直接删除,而加入的有用的点,直接找它左边和右边第一个满足上凸的点,并将中间的都删掉即可

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define db double
#define eps 1e-9
#define inf 1e9
#define son(x) (s[f[x]][1]==x)
using namespace std;
int n,s[N][2],v[N],f[N],rt;
db l[N],r[N],a[N],b[N],X[N],Y[N],g[N],rat[N];
inline db slp(int j,int k){
    return fabs(X[j]-X[k])<eps?-inf:(Y[j]-Y[k])/(double)(X[j]-X[k]);
}
inline void rot(int x){
    int y=f[x],d=son(x),g=f[y];
    s[y][d]=s[x][!d]; f[s[y][d]]=y;
    if(g) s[g][son(y)]=x; f[x]=g;
    s[x][!d]=y; f[y]=x;
}
inline void splay(int x,int r=0){
    for(int p;(p=f[x])!=r;rot(x))
        if(f[p]!=r && son(x)==son(p)) rot(p);
    if(!r) rt=x;
}
inline void insert(int k){
    if(!rt){ rt=k; return; }
    for(int x=rt;;){
        int d=X[x]<X[k];
        if(!s[x][d]){ s[x][d]=k; f[k]=x; splay(k); return; }
        else x=s[x][d];
    }
}
inline int gPre(int k){
    int r=0;
    for(int x=s[k][0];x;){
        if(slp(x,k)<=l[x]+eps) r=x,x=s[x][1];
        else x=s[x][0];
    }
    return r;
}
inline int gSuc(int k){
    int l=0;
    for(int x=s[k][1];x;){
        if(slp(x,k)+eps>=r[x]) l=x,x=s[x][0];
        else x=s[x][1];
    }
    return l;
}
inline void ps(int k){
    int p;
    if(s[k][0]){
        p=gPre(k);
        splay(p,k);
        f[s[p][1]]=0;
        s[p][1]=0;
        l[k]=r[p]=slp(k,p);
    } else l[k]=inf;
    if(s[k][1]){
        p=gSuc(k);
        splay(p,k);
        f[s[p][0]]=0;
        s[p][0]=0;
        r[k]=l[p]=slp(k,p);
    } else r[k]=-inf;
}
inline void maintain(int k){
    splay(k); ps(k); int p;
    if(l[k]<=r[k]+eps){
        if(!s[k][0] || !s[k][1]){
            rt=s[k][0]+s[k][1];
            f[rt]=0; ps(rt);
        } else {
            p=gSuc(k);
            splay(p,k);
            rt=s[k][0];
            f[rt]=0;
            s[rt][1]=p;
            f[p]=rt;
            ps(p); ps(rt);
        }
    }
}
inline void out(int x){
    if(!x) return;
    out(s[x][0]);
    printf("%d ",x);
    out(s[x][1]);
}
inline int find(db k){
    if(!rt) return 0;
    int x=rt;
    for(;;){
        if(r[x]>k+eps) x=s[x][1]; else
        if(l[x]+eps<k) x=s[x][0];
        else return x;
    }
}
int main(){
    scanf("%d%lf",&n,g);
    for(int i=1;i<=n;++i) scanf("%lf%lf%lf",a+i,b+i,rat+i);
    for(int i=1;i<=n;++i){
        int j=find(-a[i]/b[i]);
        g[i]=max(g[i-1],a[i]*X[j]+b[i]*Y[j]);
    //  printf("%d\n",j);
        Y[i]=g[i]/(a[i]*rat[i]+b[i]);
        X[i]=Y[i]*rat[i]; insert(i); maintain(i);// out(rt); puts("");
    }
    for(int i=n;i<=n;++i) printf("%.3lf\n",g[i]);
}



C[柠檬]

不得不说这题如果想到了关键一步就基本秒掉了,然而我并没有想到
首先考虑一下怎么转移式子
设 fi f i 表示前i个贝壳能转化为多少柠檬,枚举j,发现各种无法转移
因为我们不可能去枚举 s0 s 0 那怎么办呢
注意到决策最优性,如果对于某一段,我们选取大小为 s0 s 0 的贝壳去做转化,那么这一段的开头和结尾必然也是 s0 s 0 否则我们将其分成独立的一段,一定更优
这下马上可以转移了,写成方程就是

fi=max{fj−1+vi∗(si−sj+1)2},vi=vj f i = m a x { f j − 1 + v i ∗ ( s i − s j + 1 ) 2 } , v i = v j

这里 vi v i 贝壳i的大小, si s i 表示的是i是第几个大小为 vi v i 的贝壳
那么对于每个v[i]我们维护一个单独的上凸壳,每次询问在上面二分即可,这里用vector节省空间

#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long 
#define db double
using namespace std;
vector<int> q[10010];
int n,c[10010],v[100010]; LL f[100010],s[100010];
inline LL y(int j){
    return f[j-1]+v[j]*s[j]*s[j]-2*s[j]*v[j];
}
inline db slp(int j,int k){
    return (y(j)-y(k))/(2.*v[j]*(s[j]-s[k]));
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",v+i);
        s[i]=s[c[v[i]]]+1; c[v[i]]=i;
    }
//  for(int i=1;i<=n;++i){
//      for(int j=1;j<=i;++j) if(v[i]==v[j])
//          g[i]=max(g[i],g[j-1]+v[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1));
//  }
//  for(int i=1;i<=n;++i) if(s[i]==1) q[v[i]].push_back(i);
    for(int i=1,j,k;i<=n;++i){
        k=v[i];
        if(q[k].size()<=1) q[k].push_back(i); else{
            for(int j=q[k].size()-1;j;--j)
                if(slp(q[k][j],q[k][j-1])<slp(q[k][j],i)) q[k].pop_back(); else break;
            q[k].push_back(i);
        }
        if(q[k].size()==1) j=q[k][0];
        else {
            int l=0,r=q[k].size()-1;
            for(int m;l<r;){
                m=l+r>>1;
                if(slp(q[k][m],q[k][m+1])>=s[i]) l=m+1;
                else r=m;
            }
            j=q[k][l];
        }
        f[i]=f[j-1]+v[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1);
    }
    printf("%lld\n",f[n]);
}



D[玩具装箱]

题目难度从此开始下降
对于题目里面已经给出的式子,我们直接把它翻译成代码即可

fi=min{fj+(gi−gj−L)2} f i = m i n { f j + ( g i − g j − L ) 2 }
这里 gi=si+i,si g i = s i + i , s i 表示前i个玩具长度之和
这里写一下转化式子的步骤,设k<j<i
fi=fj+(gi−gj−L)2<fk+(gi−gk−L)2 f i = f j + ( g i − g j − L ) 2 < f k + ( g i − g k − L ) 2
fj−fk<g2k−g2j+2gi∗gj−2gi∗gk−2∗gj∗L+2∗gk+L f j − f k < g k 2 − g j 2 + 2 g i ∗ g j − 2 g i ∗ g k − 2 ∗ g j ∗ L + 2 ∗ g k + L
fj+g2j+2∗gj∗L−fk−g2k−2∗gk∗L<2∗(gj−gk)∗gi f j + g j 2 + 2 ∗ g j ∗ L − f k − g k 2 − 2 ∗ g k ∗ L < 2 ∗ ( g j − g k ) ∗ g i
fj+g2j+2∗gj∗L−fk−g2k−2∗gk∗L2∗(gj−gk)<gi f j + g j 2 + 2 ∗ g j ∗ L − f k − g k 2 − 2 ∗ g k ∗ L 2 ∗ ( g j − g k ) < g i

后面题目不再重复上述过程

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define N 50010
#define LL long long
using namespace std;
int n,L;
LL s[N],g[N],f[N],q[N];
inline db y(int j){
    return f[j]+g[j]*g[j]+2*g[j]*L;
}
inline db slp(int j,int k){ return (y(j)-y(k))/(2.*(g[j]-g[k])); }
int main(){
    scanf("%d%d",&n,&L); ++L;
    for(int i=1;i<=n;++i){  
        scanf("%lld",s+i);
        s[i]+=s[i-1]; g[i]=s[i]+i;
    }
    int l=0,r=0; f[0]=0;
    for(int i=1,j;i<=n;++i){
        while(l<r && slp(q[l],q[l+1])<=g[i]) ++l; j=q[l];
        f[i]=f[j]+(g[i]-g[j]-L)*(g[i]-g[j]-L);
        while(l<r && slp(q[r-1],q[r])>slp(q[r],i)) --r; q[++r]=i;
    }
    printf("%lld\n",f[n]);
}



E[仓库建设]

经典题目之一
这个题目我们考虑倒着做,因为直接计算距离不是非常方便
先计算出只建立一个仓库的代价之和S
设 fi f i 表示最后一个仓库放在i的最大节约代价
那么就可以得到一条非常简洁的转移式子

fi=max{fj+(rj−ri)∗si−ci} f i = m a x { f j + ( r j − r i ) ∗ s i − c i }

这里 ri r i 是第i个工厂到第n个工厂的距离, si s i 是1~i个工厂的产品数量之和

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define N 1000010
#define LL long long
using namespace std;
int n,r[N],p[N],c[N],q[N];
LL s[N],f[N],S=0,g[N];
inline db slp(int j,int k){
    return (f[j]-f[k])/(db)(r[k]-r[j]);
}
int main(){
    scanf("%d",&n); 
    for(int i=1;i<=n;++i) scanf("%d%d%d",r+i,p+i,c+i),s[i]=s[i-1]+p[i];
    for(int i=1;i<n;++i) S+=(r[n]-r[i])*(LL)p[i]; S+=c[n];
    f[n]=0; int h=1,t=0; q[++t]=n;
    for(int i=n-1;i;--i){
        while(h<t && slp(q[h],q[h+1])>=s[i]) ++h;
        f[i]=f[q[h]]+(r[q[h]]-r[i])*s[i]-c[i];
        while(h<t && slp(q[t],q[t-1])<slp(q[t],i)) --t;
        q[++t]=i; *f=max(*f,f[i]);
    }
    printf("%lld\n",S-*f);
}   



F[Cats Transport]

终于来了几道CF的题
和上面一道题一样,我们依然先计算出只用一个feeder时的等待时间之和
让后再计算能优化多少,设 fi,j f i , j 表示用了i个feeder,最后一个在时刻j出发的答案
那么就得到了和上题几乎一模一样的式子

fi,j=max{fi−1,k+(rk−rj)∗sj} f i , j = m a x { f i − 1 , k + ( r k − r j ) ∗ s j }

注意用滚动数组就可以了,基本没有什么变化

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define db double
#define LL long long
using namespace std;
int n,m,k,q[N]; LL f[2][N],s[N],S,r[N],p[N],d[N],g[10][1000];;
inline db slp(int j,int k){ return (f[0][j]-f[0][k])/(r[k]-r[j]); }
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=2;i<=n;++i) scanf("%lld",d+i),d[i]+=d[i-1];
    for(int x,i=1;i<=m;++i){
        scanf("%d%lld",&x,r+i); r[i]-=d[x];
    }
    sort(r+1,r+1+m); n=0; r[0]=-1000;
    for(int i=1;i<=m;++i){
        if(r[i]!=r[i-1]){ r[++n]=r[i]; p[n]=1; }
        else ++p[n];
    }
    for(int i=1;i<n;++i){ 
        S+=(r[n]-r[i])*(LL)p[i]; 
        s[i]=s[i-1]+p[i]; 
    }
    for(int T=1;T<k;++T){
        f[0][n]=0; int h=1,t=0; q[++t]=n;
        for(int i=n-1;i;--i){
            while(h<t && slp(q[h],q[h+1])>=s[i]) ++h;
            f[1][i]=f[0][q[h]]+(r[q[h]]-r[i])*s[i];
            while(h<t && slp(q[t],q[t-1])<slp(q[t],i)) --t;
            q[++t]=i;
        }
        swap(f[0],f[1]);
    }
    LL A=0;
    for(int i=1;i<=n;++i) A=max(A,f[0][i]);
    printf("%lld\n",S-A);
}



G[Product Sum]

也是一个比较简单的题
我们设 fi f i 表示移动i能获得最大的贡献
那么考虑把这个i移动到j这个位置,令 si=∑ij=1ai s i = ∑ j = 1 i a i 就得到转移式子

fi=max{si−sj+(j−i)∗ai} f i = m a x { s i − s j + ( j − i ) ∗ a i }

注意到这里并没有i<j的限制,所以我们要选择一项:
1.做两次
2.先求凸包再二分
肯定是第二项比较方便辣

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long
using namespace std;
int n,m,q[200010];
LL f[200010],v[200010],s[200010],S;
inline db slp(int j,int k){
    return (s[j]-s[k])/(j-k);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%lld",v+i),s[i]=s[i-1]+v[i],S+=v[i]*i;;
    int t=0; q[++t]=0;
    for(int i=1;i<=n;++i){
        while(1<t && slp(q[t-1],q[t])>slp(q[t],i)) --t;
        q[++t]=i;
    }
    for(int i=1;i<=n;++i){
        int l=1,r=t;
        for(int m;l<r;){
            m=l+r>>1;
            if(slp(q[m],q[m+1])<v[i]) l=m+1;
            else r=m;
        }
        f[i]=s[i]-s[q[l]]+(q[l]-i)*v[i];
        *f=max(*f,f[i]);
    }
    printf("%lld\n",*f+S);
}



H[Levels and Regions]

这个题需要推一推式子,然而我期望这方面技巧极差
首先推一推打通第i关所需要的时间Ti,设i所在的Region为[l,r]
那么

Ti=Ti∗∑i−1j=ltj∑ij=ltj+1 T i = T i ∗ ∑ j = l i − 1 t j ∑ j = l i t j + 1

设 p=ti∑ij=ltj p = t i ∑ j = l i t j 那么就得到 Ti=(1−p)Ti+1 T i = ( 1 − p ) T i + 1 就是 Ti=1+p−1 T i = 1 + p − 1
那么整个Region的期望时间E(l,r)就是 E(l,r)=∑ri=l∑ij=ltjti E ( l , r ) = ∑ i = l r ∑ j = l i t j t i
为了方便dp,我们将这个式子转化一下,首先设 Si=∑ij=1ti S i = ∑ j = 1 i t i
E(l,r)=∑i=lrSj−Sl−1ti=∑i=lrSiti−Sl−1∗∑i=lr1ti E ( l , r ) = ∑ i = l r S j − S l − 1 t i = ∑ i = l r S i t i − S l − 1 ∗ ∑ i = l r 1 t i

这里预处理一下 Ai=∑ij=1Sjtj,Bi=∑ij=11tj A i = ∑ j = 1 i S j t j , B i = ∑ j = 1 i 1 t j 就可以了
最后的dp式子是这样的:
fk,i=min{fk−1,j+Ai−Aj−Sj∗(Bi−Bj)} f k , i = m i n { f k − 1 , j + A i − A j − S j ∗ ( B i − B j ) }
剩下的就是套路而已

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200010
#define db double
using namespace std;
int n,k,q[N];
db DP[2][N],AA[N],BB[N],s[N],v[N];
inline db y(int j){
    return DP[0][j]-AA[j]+s[j]*BB[j];
}
inline db slp(int j,int k){
    return (y(j)-y(k))/(s[j]-s[k]);
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i){
        scanf("%lf",v+i);
        s[i]=s[i-1]+v[i];
        AA[i]=AA[i-1]+s[i]/v[i];
        BB[i]=BB[i-1]+1./v[i];
    }
    for(int i=1;i<=n;++i) DP[0][i]=AA[i];
    for(int T=2;T<=k;++T){
        int l=1,r=0; q[++r]=0;
        for(int i=1,j;i<=n;++i){
            while(l<r && slp(q[l],q[l+1])<BB[i]) ++l;
            j=q[l];
            DP[1][i]=DP[0][j]+AA[i]-AA[j]-s[j]*(BB[i]-BB[j]);
            while(l<r && slp(q[r-1],q[r])>=slp(q[r],i)) --r;
            q[++r]=i;
        }
        swap(DP[0],DP[1]);
    }
    printf("%.7lf\n",DP[0][n]);
}



I[序列分割]

回到Bzoj了
发现这个题,无论什么顺序分割序列,最终答案只和分割位置有关
那么计算一下发现就是每个块两两相乘,得到式子
设 fi,j f i , j 表示做到j,用了i块的最大结果
fi,j=max{fi−1,k+(sj−sk)∗sk},si=∑ij=1ai f i , j = m a x { f i − 1 , k + ( s j − s k ) ∗ s k } , s i = ∑ j = 1 i a i
滚动数组就没了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long
using namespace std;
int n,k,q[100010]; LL f[2][100010],s[100010];
inline LL y(int j){ return f[0][j]-s[j]*s[j]; }
inline db slp(int j,int k){
    if(s[k]==s[j]) return 1e100;
    return (y(j)-y(k))/(s[k]-s[j]);
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i) scanf("%lld",s+i),s[i]+=s[i-1];
    for(int i=1;i<=k;++i){
        int l=1,r=0; q[++r]=0;
        for(int j=1;j<=n;++j){
            while(l<r && slp(q[l],q[l+1])<s[j]) ++l;
            f[1][j]=f[0][q[l]]+(s[j]-s[q[l]])*s[q[l]];
            while(l<r && slp(q[r],q[r-1])>slp(q[r],j)) --r;
            q[++r]=j;
        }
        swap(f[0],f[1]);
    }
    printf("%lld\n",f[0][n]);
}



J[特别行动队]

前面那么多例题,这个题就不说了吧,注意a是负的就行了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long
using namespace std;
int n,m,q[1000010],a,b,c;
LL f[1000010],v[1200010],s[1200010],S;
inline LL y(int j){ return f[j]+a*s[j]*s[j]-b*s[j]; }
inline db slp(int j,int k){
    return (y(j)-y(k))/(s[j]-s[k]);
}
int main(){
    scanf("%d%d%d%d",&n,&a,&b,&c);
    for(int i=1;i<=n;++i) scanf("%lld",v+i),s[i]=s[i-1]+v[i];
    int l=1,r=0; q[++r]=0;
    for(int i=1;i<=n;++i){
        while(l<r && slp(q[l],q[l+1])>2.*a*s[i]) ++l;
        int j=q[l];
        f[i]=f[j]+a*(s[i]-s[j])*(s[i]-s[j])+b*(s[i]-s[j])+c;
        while(l<r && slp(q[r-1],q[r])<slp(q[r],i)) --r; q[++r]=i;
    }
    printf("%lld\n",f[n]);
}
斜率优化dp小结 单调队列优化在写斜率优化之前,我们来回顾一下单调队列优化的dp 1. 对于如下形式的dp方程 dp[i]=min{dp[j]+f(j)}(0<j<i)dp[i] = min\{dp[j] + f(j)\} (0 < j < i) 我们直接用一个变量维护(0, i)中dp[j] + f(j)的最小值即可2.对于如下形式的dp方程 dp[i]=min{dp[j]+f(j)}(i−m<j<i)dp 阅读详情

相关推荐

学习笔记——斜率优化 dp

引入 斜率优化,是单调队列优化的一个进阶版本,为了更好地理解,先来回顾一下单调队列吧~ 所谓单调队列优化,就是对于形如: dpi=max⁡{dpj+aj} dp_i=\max\{dp_j+a_j\} dpi​=max{dpj​+aj​} 的 dpdpdp 式,我们把所有的 dpj+ajdp_j+a_jdpj​+aj​ 放进单调队列里,实现 O(1)O(1)O(1) 的转移。 这个时候,只有在式子中,每一项只有关于 jjj 或者只有关于 iii 的。但是如果有这样一个式子: dpi=max⁡{dpj+aj×a

ZCETHAN 的博客 562

【详解】斜率优化 DP

斜率优化详解+凸包详解

2403_87021226的博客 2344

解决vscode 连接服务器报错:The remote host may not meet VS Code Server‘s prerequisites for glibc and libstdc++

解决vscode远程连接服务器报错:The remote host may not meet VS Code Server's prerequisites for glibc and libstdc++ (The remote host does not meet the prerequisites for running VS Code Server)

qq_37200100的博客 9909

斜率dp

斜率dp类似这种情况 dp[i]=dp[j]+f(i,j) 或者简单一点 dp[i]=dp[j]+a[i]+a[j]这种,i是1e5级别的; 一般解题步骤: 1:求出状态转移方程 2:求出 y,x,k 其中y中要不含除x以外的变量 3:判断是维护下凸包还是上凸包,具体判断方法为在队头能取到题目要求的截距最值; 技巧: 1:当题目不满足连续的性质时,要进行排序等操作,使他们满足连续取...

hutwuguangrong的博客 519

安鸾渗透测试平台-CTF系列-bash

工具Xshell 公网VPS接收反弹shell Xshell新手的下载及安装教程(超详细)_新手程序员攀爬之路的博客-优快云博客_xshell使用教程 Xshell连接后 #!/bin/bash cat ${0} while : do echo "$" read input output=`$input` 显示了一个文件,不过咋做呢?这里可能考察的是linux的语法 方法 输入bash 获得shell cat ${0} while : do .

AAAAAAAAAAAA66的博客 2689

TMC步进电机驱动stealthChop

经过九九八十一难,芯片手册拜读了好多遍,找了好多资料,问了好多人使用TMC2660驱动步进电机终于成功了。最后的问题居然是硬件把管脚画错了,然后我又没有检查,哭。。。

那可真是太开心了的博客 4489

论斜率优化dp

首先,加上机器启动时间,我们直接把之后所有的费用系数求和再乘以机器启动时间,这就是无后效性。但是呢,我们可以把若干个任务并做一个,费用系数,完成耗时都求和,只是不需要多次启动机器了。那么哪个点离直线最近呢,显然是连接两条斜率分别大于和小于当前直线的线段的点。因为之前任务已经花费的时间会算到当前任务上,且启动机器时间已经算过了。对于新插入的点,肯定是斜率越小越好,这下动态维护下凸包也可以一并解决。显然的,一个下凸包,我们动态维护凸包,这样就有了单调性。的时间启动机器,做每个任务都需要一定时间,假设在。

senlinguyvan1的博客 1318

激光SLAM算法性能对比:在Ubuntu20.04上实测Point-LIO/FAST_LIO2/Faster-LIO的运行效果

本文在Ubuntu 20.04平台上对Point-LIO、FAST-LIO2和Faster-LIO三款激光SLAM算法进行了深度实测与性能对比。通过量化分析绝对轨迹误差、CPU/内存占用及单帧处理延迟等核心指标,结合室内外场景数据,为高精度测绘、服务机器人及自动驾驶等不同应用场景提供了清晰的选型指南和实战调优建议。

weixin_28335283的博客 368

DP斜率优化

DP斜率优化   DP斜率优化,实际上就是以斜率作为比较的基准,使用单调队列优化的方法,使用斜率优化的问题应当具有这样的特征——状态转移方程是一个关于dp[i]和dp[j]的线性方程,也即dp[i]与dp[j]具有线性关系。   这样我们在求解dp[i]时,实际上就是求解一个点(dp[j],j),使得过该点的dp[i]的值最小,由于斜率是固定的,这导致我们只需要寻找与dp[j]的点形成的凸包相切的那一点作为最优转移点即可,实际求解过程中,我们只需要用单调队列维持边界上的点,再用二分查找的方式确定相切的点即可

qq_37957064的博客 668

二十八.国民技术MCU开发之UID获取与应用

在国民NT MCU中均有一个96位和128位的唯一设备标识符,其中UCID128 位, UID 为 96 位。手册中描述的作用是:通常用来做为序列号或作为密码,在编写闪存时,将此唯一标识与软件加解密算法相结合,进一步提高代码在闪存存储器内的安全性,也可用于激活带安全功能的自举程序(SecureBootloader)。UCID 和 UID,遵守国民技术芯片序列号定义,它包含芯片生产及版本相关信息。

AIoT深度探索者 | 嵌入式系统架构师 深耕物联网(IoT)与人工智能(AI)融合技术,聚焦​​边缘计算、图像开发、低功耗通信协议​​,致力于智能硬件,关注我获取最新技术文章信息与海量资源~ 1676

自注意力机制(SelfAttention Mechanism)原理与代码实战案例讲解

自注意力机制(Self-Attention Mechanism)原理与代码实战案例讲解 作者:禅与计算机程序设计艺术 / Zen and the Art of Computer Programming 1. 背景介绍

AI天才研究院 1289

斜率优化DP

斜率优化DP题外话考试的时候被这个玩意弄得瑟瑟发抖 大概是Day4(http://www.cnblogs.com/cjyyb/p/7705308.html) 小蒟蒻表示根本不会做….. 然后自己默默地搞了一下斜率优化算是开始吗??其实我讲的会非常非常非常简单,,,而且绝对没有一张图(因为我绘图水平太菜) 貌似没太多友善的题目可以用来搞….算了 虚一点,缥缈一点的来说吧….其实我就是写给自己

小蒟蒻yyb的博客 1354

9.23华为OD机试真题 新系统 - 小菊的寻宝之旅 (Java/Py/C/C++/Js/Go)

9.23华为OD机试真题 新系统 - 小菊的寻宝之旅 (Java/Py/C/C++/Js/Go)

算法大师! 978

斜率优化 DP 总结

一般来说,斜率优化DP 的题目会比较复杂,给的信息比较多,需要抽象出 准确的转移式。发现若当前新加入的点与队尾的连线斜率小了,可以把队头出队,直到斜率单调。时,提前计算本次启动 对 后面所有任务费用的增量,直接加到。这就是 斜率优化 DP 的第一步,写成朴素的 DP 转移式,同样是 “一段一段” 的 DP,唯一需要注意的是决策上界。顾名思义,运用数形结合的思想,将 DP 中求解的。的直线,我们考虑找到使得 截距 最大的那个决策点。但本题有个不太好处理的点,机器启动的时间。

qq_56326461的博客 417

世界职业院校技能大赛财经赛道项目参考逐字稿五

世界职业院校技能大赛财经赛道项目参考逐字稿五

我是网络安全兼技能大赛工程师,专注网络安全技术学习与技能大赛实战!持续分享最新的技术文章,帮你少走弯路,一起在技术赛道上进步~ 126

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

斜率优化DP——AcWing 303. 运输小猫

斜率优化DP(Slope Optimization Dynamic Programming)是一种高级动态规划技巧,用于优化具有特定形式的状态转移方程。它主要应用于那些状态转移涉及求极值(如最小值或最大值)的问题中,通过分析状态转移函数的斜率特性,将原本需要进行多次比较的操作转化为对斜率的管理,从而减少计算量。斜率优化的核心在于利用函数的单调性,通过维护一个数据结构(如单调队列)来避免重复计算,达到优化的目的。

u014114223的博客 831

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

[学习笔记]斜率优化dp 总结

我们学过不少优化类的算法了,大部分都是基于凸函数的性质给出的优化,比如Slope Trick,Wqs二分,又比如今天的斜率优化(不知道什么时候会有空把Slope Trick写掉)当dp式子满足cy−cxby−bx≤−aiby​−bx​cy​−cx​​≤−ai​的时候,我们要维护的是一个下凸包i

sophilex的博客 2137

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【笔记】【总结】斜率DP及习题

参考:斜率优化dp学习 - orzzz HDU3507 Print Article 通过本题目来分析与总结斜率DP。 给定n(5e5)和m(1000),以及一个长为n的数列AiA_iAi​,现在要把数列分成若干个连续段。 定义每个连续段的代价是(ΣAi)2+m(\Sigma A_i)^2+m(ΣAi​)2+m,求划分后的最小代价。 基础DP 设dp[i]表示把前i个数划分完的最小代价,那么: dp...

秋叶红于二月花 714

斜率DP小结

此文大部分来自以下博客 【笔记】【总结】斜率DP及习题-Little_Fall 斜率优化-南枙向暖 此文主要初学的我为了加深自己印象,难免错误,请大家小心辩别 引入 当我们在遇到这样的DP方程时dp[i]=dp[j]+(x[i]−x[j])∗(x[i]−x[j])dp[i]=dp[j]+(x[i]-x[j])*(x[i]-x[j])dp[i]=dp[j]+(x[i]−x[j])∗(x[i]−x[j...

mzip的博客 274
上一篇: 数学公式测试
下一篇: E文本加密器0.2 Aplha版
扩展的灰
博客等级 码龄12年 60粉丝 342原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值