zoukankan      html  css  js  c++  java
  • CF660F Bear and Bowling 4 [斜率优化动态规划]

    Bear and Bowling 4Bear and Bowling 4


    Descriptionmathcal{Description}
    给一个长度为NN 的序列 {ai}{a_i}, 求 maxx=1Nk+1(i=1kiax+i1)maxlimits_{x=1}^{N-k+1}( sumlimits_{i=1}^k icdot a_{x+i-1} )

    1n2×105,ai1071leq nleq 2 imes 10^5, |a_i|leq 10^7


    最初想法
    暴力: O(N)O(N) 枚举 kk, 再配合前缀和 O(N)O(N) 计算答案, 取最优值, 总共 O(N2)O(N^2).
    正解要斜率优化, 回去学习…


    正解部分
    nn 年后, 斜率优化看懂一点了… 没学过的可以点击 这里.

    sum1[i]sum_1[i] 表示前 iiaia_i 的前缀和, sum2[i]sum_2[i] 表示前 iiiaii*a_i的前缀和, val[i,j]val[i,j]表示i,ji,j之间的价值 .
    val[i,j]=sum2[j]sum2[i1](i1)(sum1[j]sum1[i1])val[i, j] = sum_2[j] - sum_2[i-1] - (i-1)*(sum_1[j] - sum_1[i-1])

    化简为 y=kx+by=kx+b 的形式进行 斜率优化,
    (i1)sum1[i1]sum2[i1]=(i1)sum1[j]+val[i,j]sum2[j](i-1)sum_1[i-1]-sum_2[i-1]=(i-1)sum_1[j]+val[i,j]-sum_2[j]
    此时

    • y=(i1)sum1[i1]sum2[i1]y=(i-1)sum_1[i-1]-sum_2[i-1]
    • k=sum1[j]k=sum_1[j]
    • x=i1x=i-1
    • b=val[i,j]sum2[j]b=val[i,j] - sum_2[j].

    鉴于求的是最大值, 所以维护上凸壳.
    kk的正负无法确定, 于是不能使用弹掉队首的方法去找最优决策点 , 只能使用二分去查找队列中第一个比 小于等于 kk 的斜率 .

    于是枚举右端点 jj 的同时将 jj 作为一个新的决策加入斜率优化的单调队列中, 用来对以后的 jj 提供决策 ii,


    实现部分

    #include<cstdio>
    #include<algorithm>
    #define reg register
    typedef long long ll;
    
    const int maxn = 2e5 + 10;
    
    int N;
    int A[maxn];
    
    ll Q[maxn];
    ll sum1[maxn];
    ll sum2[maxn];
    
    double X(int i){ return i; }
    
    double Y(int i){ return i*sum1[i] - sum2[i]; }; //!
    
    double slope(int i, int j){ return ( Y(i)-Y(j) ) / ( X(i)-X(j) ); }
    
    ll Calc(int i, int j){ return sum2[j]-sum2[i]-1ll*i*(sum1[j]-sum1[i]); }
    
    int main(){
            scanf("%d", &N);
            for(reg int i = 1; i <= N; i ++){
                    scanf("%d", &A[i]);
                    sum1[i] = sum1[i-1] + A[i];
                    sum2[i] = sum2[i-1] + 1ll*A[i]*i;
            }
            int tail = 0; ll Ans = 0;
            for(reg int j = 1; j <= N; j ++){
                    ll k = sum1[j];
                    int l = 0, r = tail;
                    while(l < r){
                            int mid = l+r >> 1;
                            if(slope(Q[mid], Q[mid+1]) > k) l = mid+1;
                            else r = mid;
                    }
                    int i = Q[r];
                    Ans = std::max(Ans, Calc(i, j));
                    while(tail >= 1 && slope(Q[tail], Q[tail-1]) < slope(Q[tail], j)) tail --;
                    Q[++ tail] = j;
            }
            printf("%I64d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    Django 前戏
    SQL基本语句
    如何正确安装Mysql
    JQuery
    解疑答惑—解决脱离标准文档流(恶心的浮动)
    事件
    卷基于快照进行恢复
    centos7下Firewall使用详解
    基于镜像卷启动的虚机快照代码分析
    nova卸载volume源码分析
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822555.html
Copyright © 2011-2022 走看看