BZOJ3156 防御准备【斜率优化DP】

xiaoxiao2025-10-01  13

Time Limit: 10 Sec Memory Limit: 512 MB

Description

Input

第一行为一个整数N表示战线的总长度。 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。

Output

共一个整数,表示最小的战线花费值。

HINT

1 &lt; = N &lt; = 1 0 6 , 1 &lt; = A i &lt; = 1 0 9 1&lt;=N&lt;=10^6,1&lt;=Ai&lt;=10^9 1<=N<=106,1<=Ai<=109


题目分析

d p [ i ] dp[i] dp[i]表示前 i i i个检查点都能通过,且第 i i i个检查点放防御塔所需最小费用 首先有 O ( n 2 ) O(n^2) O(n2)的方程 d p [ i ] = d p [ j ] + ( i − j − 1 ) ( i − j ) / 2 + a i [ i ] dp[i]=dp[j]+(i-j-1)(i-j)/2+ai[i] dp[i]=dp[j]+(ij1)(ij)/2+ai[i] j + 1 j+1 j+1~ i i i都放木偶

展开再移项 d p [ j ] + 1 2 ∗ ( j 2 + j ) = i ∗ j − 1 2 ∗ ( i 2 − i ) − a i [ i ] + d p [ i ] dp[j]+\frac{1}{2}*(j^2+j)=i*j-\frac{1}{2}*(i^2-i)-ai[i]+dp[i] dp[j]+21(j2+j)=ij21(i2i)ai[i]+dp[i] d p [ j ] + 1 2 ∗ ( j 2 + j ) dp[j]+\frac{1}{2}*(j^2+j) dp[j]+21(j2+j) y y y j j j x x x i i i为斜率进行斜率优化


#include<iostream> #include<vector> #include<algorithm> #include<queue> #include<cstring> #include<cstdio> using namespace std; typedef long long lt; typedef double dd; #define sqr(x) ((x)*(x)) lt read() { lt f=1,x=0; char ss=getchar(); while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();} while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();} return f*x; } const int maxn=2000010; int n; lt ai[maxn],dp[maxn]; int q[maxn],ll,rr; lt qans(lt i,lt j){ return dp[j]+(sqr(j)+j+sqr(i)-i)/2-i*j+ai[i];} dd calc(lt j1,lt j2) { lt ty=(dp[j2]+(sqr(j2)+j2)/2)-(dp[j1]+(sqr(j1)+j1)/2); lt tx=j2-j1; return (dd)ty/(dd)tx; } int main() { n=read(); for(int i=1;i<=n;++i) ai[i]=read(); ll=rr=1; for(int i=1;i<=n;++i) { while( ll<rr && calc(q[ll],q[ll+1])<=i ) ++ll; dp[i]=qans(i,q[ll]); while( ll<rr && calc(q[rr-1],q[rr])>=calc(q[rr],i)) --rr; q[++rr]=i; } printf("%lld",dp[n]); return 0; } 
转载请注明原文地址: https://www.6miu.com/read-5037190.html

最新回复(0)