Luogu P6047 丝之割

一道简单的斜率优化 dp。

Solution

当选择二元组 \((p,q)\) 时,对于满足 \(i>p,j<q\) 的弦 \((i,j)\):若存在弦 \((i',j')\) 满足 \(i'>i,j'<j\),在破坏弦 \((i,j)\) 时一定会破坏弦 \((i',j')\),故先删去所有的弦 \((i',j')\)

在排序后,由于弦的上坐标和下坐标分别都单调递增,考虑 dp 分划阶段。

\(c_i=\min\limits_{k=1}^{i} a_i,d_i=\min\limits_{k=i}^{n} b_i\),容易得到状态转移方程:

\[dp_i=\min_{j<i} \{dp_j+c_{u_{j+1}-1}d_{v_{i-1}}\} \]

考虑斜率优化。将式子转化为 \(y=kx+b\) 的形式,有:

\[\begin{cases} x=-c_{u_{j+1}-1} \\ y=dp_j \\ k=d_{v_{i-1}} \\ b=dp_i \end{cases}\]

按照常规斜率优化 dp 套路,单调队列维护凸包斜率即可。

Code

/* ChongYun */
#include<bits/stdc++.h>
#define START_LL 1
using namespace std;
#define fir first
#define sec second
#define pii pair<int,int>
#define start(x) using namespace x
#if START_LL 
#define int long long
#endif
#define ldb long double
namespace IO{
    #define flush() fwrite(obuf,1,O-obuf,stdout)
    #define putchar(x) ((O==obuf+(1<<21))&&(flush(),O=obuf)),*O++=x
    char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    inline int read(){
        register int x=0,f=1;
        register char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline void write(int x){
        if(x>9) write(x/10);
        putchar((x%10)^48);
        return ;
    }
    struct Flush{ ~Flush(){flush();} }_;
}start(IO);
const int N=3e5+5,inf=1e18;
int n,k,a[N],b[N],c[N],d[N];
int q[N],hd=1,tl=0,dp[N];
pii Rhy[N],Mil[N];
bool cmp(pii pt,pii qt){
    if(pt.fir==qt.fir) return pt.sec<qt.sec;
    return pt.fir<qt.fir;
}
ldb getx(int qwq){ return a[Mil[qwq+1].fir-1]; }
ldb gety(int qwq){ return dp[qwq]; }
ldb Slope(int qwq,int qaq){ 
    if(getx(qwq)==getx(qaq)) return inf;
    return -(gety(qwq)-gety(qaq))/(getx(qwq)-getx(qaq)); 
}
signed main(){
	n=read(); k=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++) b[i]=read();
	for(int i=1;i<=k;i++){
        Rhy[i].fir=read();
        Rhy[i].sec=read();
    }
    sort(Rhy+1,Rhy+k+1,cmp);
    int now=n; n=1;
    int l=Rhy[1].fir,r=Rhy[1].sec;
    Mil[1]=Rhy[1];
    for(int i=2;i<=k;i++){
        if(l<=Rhy[i].fir&&Rhy[i].sec<=r) continue;
        l=Rhy[i].fir,r=Rhy[i].sec;
        Mil[++n]=Rhy[i];
    }
    k=now; 
    a[0]=b[k+1]=inf;
    for(int i=1;i<=k;i++) a[i]=min(a[i],a[i-1]);
    for(int i=k;i>=0;i--) b[i]=min(b[i],b[i+1]);
	q[++tl]=0;
    for(int i=1;i<=n;i++){
        while(hd<tl&&Slope(q[hd],q[hd+1])<=b[Mil[i].sec+1]) ++hd;
	    dp[i]=dp[q[hd]]+a[Mil[q[hd]+1].fir-1]*b[Mil[i].sec+1];
	    while(hd<tl&&Slope(q[tl],q[tl-1])>=Slope(i,q[tl])) --tl;
	    q[++tl]=i;
    }
    printf("%lld\n",dp[n]);
	return 0;
}
posted @ 2025-05-31 11:04  HAM_qwq  阅读(19)  评论(0)    收藏  举报