BZO1911 ||洛谷P3628 [APIO2010]特别行动队【斜率优化DP】

xiaoxiao2025-09-16  111

Time Limit: 4 Sec Memory Limit: 64 MB

Description

Input

Output

HINT


题目分析

斜率优化DP–详解

首先容易想到一个简单的 O ( n 2 ) O(n^2) O(n2)算法 d p [ i ] dp[i] dp[i]表示前 i i i个士兵分组能得到的最大战斗力 d p [ i ] = m a x (   d p [ j ] + a ∗ ( s u m [ i ] − s u m [ j ] ) 2 + b ∗ ( s u m [ i ] − s u m [ j ] ) + c   ) dp[i]=max(\ dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c\ ) dp[i]=max( dp[j]+a(sum[i]sum[j])2+b(sum[i]sum[j])+c )

然后把平方拆开,移项 d p [ j ] + a ∗ s u m [ j ] 2 − b ∗ s u m [ j ] = 2 a ∗ s u m [ i ] ∗ s u m [ j ] − a ∗ s u m [ i ] 2 − b ∗ s u m [ i ] − c + d p [ i ] dp[j]+a*sum[j]^2-b*sum[j]=2a*sum[i]*sum[j]-a*sum[i]^2-b*sum[i]-c+dp[i] dp[j]+asum[j]2bsum[j]=2asum[i]sum[j]asum[i]2bsum[i]c+dp[i] d p [ j ] + a ∗ s u m [ j ] 2 − b ∗ s u m [ j ] dp[j]+a*sum[j]^2-b*sum[j] dp[j]+asum[j]2bsum[j] y y y s u m [ j ] sum[j] sum[j] x x x 2 a ∗ s u m [ i ] 2a*sum[i] 2asum[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; lt n,a,b,c; lt sum[maxn],dp[maxn]; int q[maxn],ll,rr; lt qans(int i,int j){ return dp[j]+a*sqr(sum[j])-b*sum[j]-2*a*sum[i]*sum[j]+a*sqr(sum[i])+b*sum[i]+c;} dd calc(int j1,int j2) { lt ty=(dp[j2]+a*sqr(sum[j2])-b*sum[j2])-(dp[j1]+a*sqr(sum[j1])-b*sum[j1]); lt tx=sum[j2]-sum[j1]; return (dd)ty/(dd)tx; } int main() { n=read();a=read();b=read();c=read(); for(int i=1;i<=n;++i) { int x=read(); sum[i]=sum[i-1]+x; } ll=rr=1; for(int i=1;i<=n;++i) { while( ll<rr && calc(q[ll],q[ll+1]) >= 2*a*sum[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-5036444.html

最新回复(0)