• [CSP2019] 划分 解题报告


    [CSP2019] 划分

    题意

    有一个长度为 (n) 的序列 (a_i) ((n le 4 imes 10^7)), 求

    [(sum_{i=1}^{k_1} a_i)^2 + (sum_{i=k_1+1}^{k_2} a_i)^2 dots (sum_{i=k_{j-1}+1}^{n} a_i)^2 ]

    的最小值.

    思路

    结论: 上述式子能取到最小值, 当且仅当最后一块 (即(sum_{i=k_{j-1}+1}^{n} a_i)) 取到了最小值.
    证明: 暂时不会.

    那我们就 (dp) 保证最后一块最小就行了.

    (val[i]) 为以 (i) 结尾的序列的最后一块的最小值.

    那么对于每一位 (i) 只需从 (i-1)(0) 找到第一位 (j) 满足 (sum[i] - sum[j] ge val[j]), (val[i]) 即为 (sum[i]-sum[j]). ((sum) 为前缀和数组)

    可以发现, 每次 (j) 值是有单调性的, 所以可以考虑单调队列优化.

    队头的筛选很简单, 满足要求就 +1, 找到最后一个满足条件的 (j) 即可.

    再考虑队尾的处理, 如果只是单纯的把当前的 (i) 加入队列中的话, 就会出现 "队列中后面满足但前面不满足的情况",
    比如说下面这个例子.

    7 0
    15 19 14 1 5 7 17

    (lst[i])(i) 的上一个块的终点.

    在上面这个例子中, (lst[6]=2), 那么 (i==7) 时, 队头 (t1) 就会在 (2) 的位置,
    但是, 由于 (lst[3]=1, val[3]=33), 而 (sum[7]-sum[3]==30 < val[3]), 所以 (t1) 会停在 (3).

    但是, (lst[5]=2), 所以 (lst[7]) 实际上是可以取到 (5) 的.

    所以, 我们可以发现, 要在加入一个新的选项时, 要去除一些不优情况.

    首先想到的是把队列中 (val[que[t2]] > val[i]) 的去掉, ( (t2) 为队尾 )
    但是这样可能会导致后面的一些 (i) 取不到满足要求的 (j),

    所以我们还要保证当 (que[t2]) 对于后面的某个数满足要求时, (i) 也一定满足要求.

    (t) 为后面的一个点, 那么就要满足: (sum[t]-sum[que[t2]] ge val[que[t2]]) 可以推导到 (sum[t]-sum[i] ge val[i]).
    即 $ val[que[t2]] + sum[que[t2]] ge val[i] + sum[i] $,

    那么, 在把 (i) 加入队尾的时候判断上述条件, 若满足则 (t2--).

    代码

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=5e5+7;
    int n,ty,que[N],t1=1,t2,pre[N];
    ll a[N],sum[N],val[N],ans;
    int main(){
      cin>>n>>ty;
      for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
      }
      que[++t2]=0;
      for(int i=1;i<=n;i++){
        while(t1<t2&&sum[i]-sum[que[t1+1]]>=val[que[t1+1]]) t1++;
        pre[i]=que[t1];
        val[i]=sum[i]-sum[que[t1]];
        while(t2>=t1&&val[i]+sum[i]<=val[que[t2]]+sum[que[t2]]) t2--;
        que[++t2]=i;
      }
      int p=n;
      while(p){
        ans+=val[p]*val[p];
        p=pre[p];
      }
      printf("%lld
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    Java基础-四要素之一《继承》
    Java基础-四要素之一《多态》
    Java基础-四大特性理解(抽象、封装、继承、多态)
    Java基础-父类-子类执行顺序
    Java基础--重写(Overriding,覆盖)-重载(Overloading)
    Java基础-数据类型转换
    Java基础-转义字符
    Java基础-数据类型int,short,char,long,float,double,boolean,byte
    算法-科学计算法
    Java基础-JVM堆与栈
  • 原文地址:https://www.cnblogs.com/BruceW/p/12006359.html
Copyright © 2020-2023  润新知