BZOJ 1911 [APIO2010]特别行动队


题目描述
这里写图片描述


因为是从别人博客里斜率优化分类一栏找的题目,所以…这题被我秒了。

显然先预处理前缀和s(i)=ik=1xi
d(i) 为将前i 个士兵分组的最大修正后战斗力。

d(i)===max{ d(j)+a(s(i)s(j))2+b(s(i)s(j))+c }max{ d(j)+a×s(i)22a×s(i)s(j)+a×s(j)2+b×s(i)b×s(j)+c }max{ d(j)2a×s(i)s(j)+a×s(j)2b×s(j) }+a×s(i)2+b×s(i)+c


KiXjBiYj====2a×s(i)s(j)d(i)a×s(i)2b×s(i)cd(j)+a×s(j)2b×s(j)

直线解析式为KiXj+Bi=Yj 其中斜率Ki 单减,Xj 单增。
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#define k(A) (2*a*s[A])
#define x(A) s[A]
#define b(A) (d[A]-a*s[A]*s[A]-b*s[A]-c)
#define y(A) (d[A]+a*s[A]*s[A]-b*s[A])
using namespace std;
const int maxn=1000010;
long long d[maxn],s[maxn];
int q[maxn],n,a,b,c;
double slope(int i,int j){
    return 1.0*(y(i)-y(j))/(x(i)-x(j));
}
int main(){
    cin>>n>>a>>b>>c;
    s[0]=q[0]=d[0]=0;
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        s[i]=s[i-1]+x;
    }
    int head=0,tail=0;
    for(int i=1;i<=n;i++){
        while(head<tail&&slope(q[head],q[head+1])>k(i)) head++;
        d[i]=-(k(i)*x(q[head])-y(q[head])-a*s[i]*s[i]-b*s[i]-c);
        while(head<tail&&slope(q[tail-1],q[tail])<=slope(q[tail],i)) tail--;
        q[++tail]=i;
    }
    cout<<d[n]<<endl;
}
发布了59 篇原创文章 · 获赞 4 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章