题目:CF1175D.
题目大意:给定一个长度为
n的数组
a,要求划分成
k块(不能有块为空).设
ai所在块的编号为
f(i),则求出最大的
∑i=1naif(i).
1≤k≤n≤3∗105,∣ai∣≤106.
看到这道题的时候感觉像是个DP,然后一看数据范围
1≤k≤n≤3∗105,然而我能想到的状态都是
O(nk)的…
于是后面开始死命想贪心,想到大概只剩半个小时的时候,实在感觉贪心不行,只好硬着头皮DP了…
先是想了个顺着推的DP,设
f[i][j]表示
a1到
ai划分成
j组的最大答案,容易想到DP方程:
f[i][j]=max{f[i−1][j],f[i−1][j−1]}+a[i]∗j
发现这个方程与
i和
j都有关,一下子就觉得没办法优化了…
所以再想了个倒着推的DP,设
f[i][j]表示
ai到
an划分成
j组的最大答案,容易列出方程:
f[i][j]=max{f[i+1][j]+a[i],f[i+1][j−1]+k=i∑na[k]}=max{f[i+1][j],f[i+1][j−1]+k=i+1∑na[k]}+a[i]
然后我们设
A数组为
a的后缀和,即
A[i]=∑j=ina[j],就可以把方程变为:
f[i][j]=max{f[i+1][j],f[i+1][j−1]+A[i+1]}+a[i]
然后我们会发现,这个东西相当于是在
A[1]到
A[n]中选
k个数并且强制选
A[1]的情况下,使得和最大.
很容易想到这个东西就是贪心给
A[2]到
A[n]排下序找到前
k−1大求个和再加个
A[1]就是答案.
时间复杂度
O(nlogn).
代码如下:
#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;
}