我是云领橙长孟令航
题目链接
1.题目重述
给定 n n n头奶牛,每头奶牛工作效率不同,奶牛 i i i的工作效率为 E i E_i Ei,求在至多 k k k只连续的奶牛的情况下,求最大效率值
2.思考算法
如果直接计算最大效率值,就要用双层循环,时间复杂度是
O
(
n
2
)
O(n^2)
O(n2),在
n
n
n等于
10
5
10^5
105的情况下,
n
2
n^2
n2为
10
10
10^{10}
1010,会超时,所以我们要想更优的办法
正难则反,如果我们计算删除哪些奶牛后,既符合至多
k
k
k只连续的奶牛,有保证删除的是最优的(即最小效率的),那么用效率和减删去的最小效率也就是最大效率值
考虑
d
p
dp
dp,让
d
p
i
dp_i
dpi表示为第
i
i
i个奶牛被移除(不选)时,前
i
i
i个奶牛中移除奶牛的最小效率总和,那么要求出最小移除代价,就需要求出每
k
k
k个连续序列中的最小值,直接求时间复杂度可达
O
(
n
k
)
O(nk)
O(nk),当
k
k
k接近于
n
n
n时,还有可能超时,要快速求每
k
k
k个连续序列中的最小值,考虑单调队列
算法步骤:
1.单调队列移除元素
弹出不可能作为答案值和过期值
2.动态转移
当前值等于前面
k
k
k个值中的最小值(就是前面距离该奶牛最近的效率最小的删除奶牛)加上删除代价
3.输出答案
即为效率和减删去的最小效率
code:
#include<bits/stdc++.h>
using namespace std;
//使用long long防止溢出,因为Ei可达10^9,N可达10^5,总和可达10^14
typedef long long ll;
ll a[100003];//a...a[N]存储效率a[n + 1]为虚拟节点
ll dp[100003];//dp[i]表示第i头奶牛被移除(不选)时,前i头奶牛被移除(不选)时,前i个奶牛中被移除奶牛的最小效率总和
ll sum = 0;
int main() {
//优化IO
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
sum += a[i];
}
a[n + 1] = 0;//虚拟节点n+1,效率为0,用于处理结尾的连续性
deque<int> dq;//单调队列,存储索引,对应的dp值单调递增
dq.push_back(0);
//++i用于加速
for (int i = 1; i <= n + 1; ++i) {
//删去过期值
while (!dq.empty() && dq.front() < i - k - 1) {
dq.pop_front();
}
if (!dq.empty()) {
dp[i] = dp[dq.front()] + a[i];
} else {
dp[i] = a[i];
}
//保持单调递增
while (!dq.empty() && dp[dq.back()] >= dp[i]) {
dq.pop_back();
}
dq.push_back(i);
}
cout << sum - dp[n + 1];
return 0;
}

609

被折叠的 条评论
为什么被折叠?



