• [APIO2010]特别行动队


    题面在这里

    题意

    你有一支由(n)名预备役士兵组成的部队,士兵从(1)(n)编号,要将他们拆分 成若干特别行动队调入战场。
    出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如((i,i+1,...,i+k))的序列。
    编号为(i)的士兵的初始战斗力为(x_i),一支特别行动队的初始战斗力(x)为队内 士兵初始战斗力之和,即(x=x_i + x_{i+1} + ... + x_{i+k})
    作为部队统帅,现在你要为这支部队进行编队,
    使得所有特别行动队修正后战斗力之和最大。求出这个最大和。

    数据范围

    [1 ≤ n ≤ 1,000,000,–5 ≤ a ≤ –1,|b| ≤ 10,000,000,|c| ≤ 10,000,000,1 ≤ xi ≤ 100 ]

    sol

    似乎仍然是一道斜率DP入门题
    我们设(f[i])表示选择前(i)名的修正战斗力最大值,那么有

    [f[i]=max_{j=0}^{i-1}(f[j]+a imes(sum_{k=j+1}^{i}x[i])^2+b imes(sum_{k=j+1}^{i}x[i])+c) ]

    (s[i]=(sum_{j=1}^{i}x[i])),有

    [f[i]=max_{j=0}^{i-1}(f[j]+a(s[i]-s[j])^2+b(s[i]-s[j])+c) ]

    [=max_{j=0}^{i-1}(f[j]-b imes s[j]+a imes s[j]^2-2a imes s[i]s[j]) ]

    [+a imes s[i]^2+b imes s[i]+c ]

    由于(a<0),故插点((2a imes s[j],f[j]-b imes s[j]+a imes s[j]^2))
    询问递增斜率(k_i=s[i])即可

    只是维护的是第三象限的上凸包!!!

    代码

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define mp make_pair
    #define pub push_back
    #define puf push_front
    #define pob pop_back
    #define pof pop_front
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const dd eps=1e-10;
    const int mod=1e8;
    const int N=1000010;
    il ll read(){
    	RG ll data=0,w=1;RG char ch=getchar();
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
    	return data*w;
    }
    
    il void file(){
    	freopen(".in","r",stdin);
    	freopen(".out","w",stdout);
    }
    
    ll n,a,b,c,s[N],f[N],L=N,R=N-1;struct node{ll x,y;}Q[N];
    //队列改啦!!!
    il void insert(node q){
    	while(L<R&&(Q[L+1].y-Q[L].y)*(Q[L].x-q.x)>=(Q[L].y-q.y)*(Q[L+1].x-Q[L].x))
    		L++;
    	Q[--L]=q;
    }
    
    il ll query(ll k){
    	while(L<R&&k*(Q[R].x-Q[R-1].x)>=Q[R].y-Q[R-1].y)
    		R--;
    	return Q[R].y-k*Q[R].x;
    }
    
    int main()
    {
    	n=read();a=read();b=read();c=read();
    	for(RG int i=1;i<=n;i++)s[i]=read()+s[i-1];
    	insert((node){0,0});
    	for(RG int i=1;i<=n;i++){
    		f[i]=query(s[i])+a*s[i]*s[i]+b*s[i]+c;
    		insert((node){2*a*s[i],f[i]-b*s[i]+a*s[i]*s[i]});
    	}
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    java实现文件上传下载至ftp服务器
    理解java代理模式
    [置顶] 理解java中的线程池
    wait,notify,非阻塞队列实现生产者,消费者模型
    理解java阻塞队列BlockingQueue
    CentOS下安装配置Nginx
    putty笔记
    CentOs下安装jdk、MySql、Redis笔记
    简述yum和apt-get的区别
    Linux 文件颜色说明
  • 原文地址:https://www.cnblogs.com/cjfdf/p/8659835.html
Copyright © 2020-2023  润新知