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