zoukankan      html  css  js  c++  java
  • Codeforce 1175 D. Array Splitting

    新鲜热乎的题 Codeforce 1175 D

    题意:给出一个长度为$n$的序列$a$,你需要把它划分为$k$段,每一个元素都需要刚好在其中一段中。分好之后,要计算$sum_{i=1}^{n} (a_i centerdot f(i))$,使这个值最大。其中$f(i)$代表第$i$个元素被分在第几段中。简单来说,就是每个元素被分在第几段中就需要乘上几,使序列的和最大。

    假设$sum$是$a$的前缀和,$k$个分割点分别为$l_j$,将序列分割为$[1, l_1],[l_1 + 1, l_2]......[l_{k-1} + 1, l_k]$,那么第$j$段对总和的贡献是$(sum_{l_j} - sum_{l_{j-1}}) * j$。

    由此,总和应该为$sum_{l_1} + (sum_{l_2} - sum_{l_1}) * 2 + (sum_{l_3} - sum_{l_2}) * 3+……+(sum_{l_k} - sum_{l_{k-1}}) * k$,很显然,相邻两项之间存在可以抵消的部分,同时$l_k$一定为$n$。将其化简:$sum_n centerdot k - sum_{l_1} - sum_{l_2} -……-sum_{l_{k-1}}$,那么我们只需要在前$n-1$项的前缀和中找出最小的$k-1$个就可以得到最大的总和了。

    int n, k;
    int a;
    ll sum[maxn];
    int main() {
        scanf("%d %d", &n, &k);
        priority_queue<ll, vector<ll>, greater<> > q;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a);
            sum[i] = sum[i - 1] + a;
            if(i != n)
                q.push(sum[i]);
        }
        ll ans = sum[n] * k;
        for(int i = 1; i <= k - 1; ++i) {//找出最小的k-1个前缀和
            ans -= q.top();
            q.pop();
        }
        printf("%lld
    ", ans);
    }
  • 相关阅读:
    APP界面设计之尺寸介绍
    设计师应该知道的那些事儿(一)
    PS制作高光导航背景
    URL长度限制
    问自己的技术问题
    JavaScript实现生成GUID(全局统一标识符)
    JS操作数组,for循环新技能get
    win7/Win8/Win10, IIS7.5/IIS8/IIS10 配置伪静态
    .NET WebAPI生成Excel
    .net WebAPI 传递对象参数
  • 原文地址:https://www.cnblogs.com/sun-of-Ice/p/10982844.html
Copyright © 2011-2022 走看看