题目地址:登录—专业IT笔试面试备考平台_牛客网
题目大致意思:给你一个长度为N(N<=2e6)的序列,并且所有的元素都是大于M(1<=M<=1e7),然后让你修改其中的一些值,使得每个长度为K(1<=K<=N)的区间和小于0,并且每个元素修改的最低值为-M,修改的权值为两个的差,求最小的总修改值。
样例:
输入:
4 5 2
7 5 8 10
输出:
32
解题方法:首先看下时间,就给了1s,而且数据的大小是2e6,那么做法基本上就是O(n)了。如果我们从前往后遍历,那么对于每个大于等于0的大小为K的区间的话我们修改的位置肯定是越往后面越好。随着区间的移动,最后一个位置的值都会在改变,很容易就想到了后进先出的关系于是就使用栈来做,而且对于每一个我们修改到-M的值的时候,都需要移出这个栈,因为这个值不能再小了。复杂度就是2*n。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N = 2e6+7;
int n, m, k;
LL sum, res;
int A[N], st[N], top;
inline int read() {
char ch = getchar();
int x = 0, f = 1;
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void put(LL x) {
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) put(x / 10);
putchar(x % 10 + '0');
}
int main() {
n = read();
m = read();
k = read();
for (int i = 1; i <= n; i++) {
A[i] = read();
}
for (int i = 1; i < k; i++) {
st[++top] = i;
sum += A[i];
}
int pos = k;
while (pos <= n) {
sum -= A[pos-k];
sum += A[pos];
st[++top] = pos;
while (sum >= 0) {
int now = st[top];
int tmp = A[now]+m;
if (tmp > sum+1) {
A[now] -= sum+1;
res += sum+1;
sum = -1;
} else {
A[now] -= tmp;
res += tmp;
top--;
sum -= tmp;
}
}
pos++;
}
put(res);
return 0;
}
代码注意地方:一个long long int类型的数组必须使用%lld读入,一个int类型的数组使用%d读入,而不能为了方便,LL类型的数组用%d读入,在这一题中我就是LL类型数组使用%d读入的,因此出现了三次的段错误。