Codeforces 1175 D Array Splitting 题解(DP+贪心)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/91164895

题目:CF1175D.
题目大意:给定一个长度为 n n 的数组 a a ,要求划分成 k k 块(不能有块为空).设 a i a_i 所在块的编号为 f ( i ) f(i) ,则求出最大的 i = 1 n a i f ( i ) \sum_{i=1}^{n}a_if(i) .
1 k n 3 1 0 5 , a i 1 0 6 1\leq k\leq n\leq 3*10^5,|a_i|\leq 10^6 .

看到这道题的时候感觉像是个DP,然后一看数据范围 1 k n 3 1 0 5 1\leq k\leq n\leq 3*10^5 ,然而我能想到的状态都是 O ( n k ) O(nk) 的…

于是后面开始死命想贪心,想到大概只剩半个小时的时候,实在感觉贪心不行,只好硬着头皮DP了…

先是想了个顺着推的DP,设 f [ i ] [ j ] f[i][j] 表示 a 1 a_1 a i a_i 划分成 j j 组的最大答案,容易想到DP方程:
f [ i ] [ j ] = max { f [ i 1 ] [ j ] , f [ i 1 ] [ j 1 ] } + a [ i ] j f[i][j]=\max \{ f[i-1][j],f[i-1][j-1]\}+a[i]*j

发现这个方程与 i i j j 都有关,一下子就觉得没办法优化了…

所以再想了个倒着推的DP,设 f [ i ] [ j ] f[i][j] 表示 a i a_i a n a_n 划分成 j j 组的最大答案,容易列出方程:
f [ i ] [ j ] = max { f [ i + 1 ] [ j ] + a [ i ] , f [ i + 1 ] [ j 1 ] + k = i n a [ k ] } = max { f [ i + 1 ] [ j ] , f [ i + 1 ] [ j 1 ] + k = i + 1 n a [ k ] } + a [ i ] f[i][j]=\max \left\{ f[i+1][j]+a[i],f[i+1][j-1]+\sum_{k=i}^{n}a[k] \right\}\\ =\max \left\{ f[i+1][j],f[i+1][j-1]+\sum_{k=i+1}^{n}a[k] \right\}+a[i]

然后我们设 A A 数组为 a a 的后缀和,即 A [ i ] = j = i n a [ j ] A[i]=\sum_{j=i}^{n}a[j] ,就可以把方程变为:
f [ i ] [ j ] = max { f [ i + 1 ] [ j ] , f [ i + 1 ] [ j 1 ] + A [ i + 1 ] } + a [ i ] f[i][j]=\max\{ f[i+1][j],f[i+1][j-1]+A[i+1] \}+a[i]

然后我们会发现,这个东西相当于是在 A [ 1 ] A[1] A [ n ] A[n] 中选 k k 个数并且强制选 A [ 1 ] A[1] 的情况下,使得和最大.

很容易想到这个东西就是贪心给 A [ 2 ] A[2] A [ n ] A[n] 排下序找到前 k 1 k-1 大求个和再加个 A [ 1 ] A[1] 就是答案.

时间复杂度 O ( n log n ) O(n\log n) .

代码如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=300000;

int n,k;
LL a[N+9],A[N+9],ans;

bool cmp(const LL &a,const LL &b){return a>b;} 

Abigail into(){
  scanf("%d%d",&n,&k);
  for (int i=1;i<=n;++i)
    scanf("%I64d",&a[i]);
}

Abigail work(){
  for (int i=n;i>=1;--i) A[i]=a[i]+A[i+1];
  sort(A+2,A+n+1,cmp);
  for (int i=1;i<=k;++i) ans+=A[i];
}

Abigail outo(){
  printf("%I64d\n",ans);
}

int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/91164895