Codeforces 1197C 贪心+思维好题


传送门:Codeforces 1197C


Array Splitting
time limit per test:2 seconds
memory limit per test:256 megabytes
inputstandard input
outputstandard output

Problem Description
You are given a sorted array a1,a2,…,an (for each index i>1 condition ai≥ai−1 holds) and an integer k.
You are asked to divide this array into k non-empty consecutive subarrays. Every element in the array should be included in exactly one subarray.
Let max(i) be equal to the maximum in the i-th subarray, and min(i) be equal to the minimum in the i-th subarray. The cost of division is equal to ∑ i = 1 k ( m a x ( i ) − m i n ( i ) ) \displaystyle\sum_{i=1}^k{(max(i)-min(i))} i=1k(max(i)min(i)). For example, if a=[2,4,5,5,8,11,19] and we divide it into 3 subarrays in the following way: [2,4],[5,5],[8,11,19], then the cost of division is equal to (4−2)+(5−5)+(19−8)=13.
Calculate the minimum cost you can obtain by dividing the array a into k non-empty consecutive subarrays.

Input
The first line contains two integers n and k (1≤k≤n≤3⋅105).
The second line contains n integers a1,a2,…,an (1≤ai≤109, ai≥ai−1).

Output
Print the minimum cost you can obtain by dividing the array a into k nonempty consecutive subarrays.

Sample Input
6 3
4 8 15 16 23 42
4 4
1 3 3 7
8 1
1 1 2 3 5 8 13 21

Sample Output
12
0
20




题意:
给你一个长度为n的由小到大排完序的数组,要你把他分成k段,每段的价值为给段的最大值减去最小值,问你怎么分才能使分段的和最小。


题解:
本来这题也不会的,经一个大佬的点拨才ac。
因为题目已经说明给你的是一个排完序的数组,那么既然要求最大值最小值之差,我们不妨做个差分。有一点需要相通,我们求一个排完序区间的最大值最小值之差,其实就是这段区间相连两个数差分的和。同样的,如果我们求出了一个区间里的所有差分,那么我们从中去掉一个差分的意思就是在某位置将原序列分成两段。
我们要将原序列分成k段,那么就应该在差分序列里去掉k-1个数,剩下的差分序列的合,就是我们分下的几个区间的最大值最小值之和。

所以贪心的策略就是:去掉差分序列里最大的k-1个数,然后求差分序列的合即可。




AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=110000;
ll a[3*N];//原序列
ll b[3*N];//差分序列
int n,k;
int main()
{
  scanf("%d%d",&n,&k);
  for(int i=1;i<=n;i++)
  {
    scanf("%I64d",&a[i]);
  }
  if(n==k)
  {
    printf("0\n");
  }
  else if(k==1)
  {
    printf("%I64d\n",a[n]-a[1]);
  }
  else
  {
    for(int i=1;i<=n-1;i++)
    {
      b[i]=a[i+1]-a[i];
    }
    sort(b+1,b+n);
    ll sum=0;
    for(int i=1;i<=n-k;i++)
    {
      sum+=b[i];
    }
    printf("%I64d\n",sum);
  }
  return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值