zoukankan      html  css  js  c++  java
  • [APIO 2010] 特别行动队

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=1911

    [算法]

             设前i个士兵"修正"后的最大战斗力为fi

             令sumi表示x的前缀和

             显然 , 有状态转移方程 : fi = max{ fj + a * (sumi - sumj) ^ 2 + b * (sumi - sumj) + c }

             对该式进行化简 , 得 :

             fi = max{ fj + asumi ^ 2 + asumj ^ 2 - 2asumisumj + bsumi - bsumj + c}

            令Yj = fj + asumj ^ 2 , Xj = sumj

             则 : fi = max{Yj - Xj(2sumi + b) + aumi ^ 2 + bsumi + c}

             那么Yj = Xj + (2asumi + b) + fi - asumi ^ 2 - bsumi - c

             显然我们要做的是最大化截距

             2asumi + b单调递减 , Xi单调递增 , 维护一个上凸壳即可

             时间复杂度 : O(N)

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1000010;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    int n , l , r;
    ll a , b , c;
    int q[N];
    ll f[N] , sum[N] , X[N] , Y[N];
    
    template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
    template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    
    int main()
    {
            
            read(n);
            read(a); read(b); read(c);
            for (int i = 1; i <= n; i++)
            {
                    int x;
                    read(x);
                    sum[i] = sum[i - 1] + x;
                    X[i] = sum[i];
            }
            f[q[l = r = 1] = 0] = 0;
            for (int i = 1; i <= n; i++)
            {
                    while (l < r && Y[q[l + 1]] - Y[q[l]] >= (2 * a * sum[i] + b) * (X[q[l + 1]] - X[q[l]])) ++l;
                    f[i] = Y[q[l]] - X[q[l]] * (2 * a * sum[i] + b) + a * sum[i] * sum[i] + b * sum[i] + c;
                    Y[i] = f[i] + a * sum[i] * sum[i];
                    while (l < r && (Y[i] - Y[q[r]]) * (X[q[r]] - X[q[r - 1]]) >= (Y[q[r]] - Y[q[r - 1]]) * (X[i] - X[q[r]])) --r;
                    q[++r] = i;        
            }
            printf("%lld
    " , f[n]);
            
            return 0;
        
    }
  • 相关阅读:
    CentOS挂载NTFS移动硬盘
    【算法与数据结构】动态规划
    【算法与数据结构】图的最小生成树 MST
    【C语言工具】AddressSanitizer
    【算法与数据结构】二叉堆和优先队列 Priority Queue
    【算法与数据结构】三种简单排序
    【算法与数据结构】并查集 Disjoint Set
    【算法与数据结构】二叉堆和堆排序
    【Linux 应用编程】进程管理
    【Linux 应用编程】进程管理
  • 原文地址:https://www.cnblogs.com/evenbao/p/10354200.html
Copyright © 2011-2022 走看看