题目链接:点击跳转
题意: 有两个长度相等的序列a,b,a序列开始全为0,b序列有题目给出,每次可以选择a中一段长度为k的序列,将该范围的数依次加上1,2,3…k,问最少多少次操作,能使对于任意i,使得ai >= bi。
思路: 最后一位只能够使用k来消除,而用k消除也恰好是最快的,那么可以从后往前开始处理,但是要怎么更新序列呢,可以使用差分来给修改的每位都加上i(操作次数),用线段树来维护差分序列,求出的前缀和就是该点的值,从后往前处理一遍即可。
代码如下:
#include<bits/stdc++.h>
#include <ostream>
using namespace std;
typedef long long ll;
#define endl '\n'
typedef pair<int, int> PII;
#define debug() cout.flush()
#define for0(i, a) for (int i = 0; i < a; ++i)
#define REP(i, a, b) for (int i = a; i < b; ++i)
#define FOR(i, a, b) for (int i = a; i <= b; ++i)
#define REPC(i, a, b, c) for (ll i = a; i < b && i < c; ++i)
#define RREP(i, a, b) for (int i = a; i >= b; --i)
const ll MOD = 1e9 + 7;
const ll mod = 998244353;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 5e3;
inline void init() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
int n, k;
ll sum[MAXN << 2], a[MAXN], lazy[MAXN << 2];
inline void pushup(int x) {
sum[x] = sum[x << 1] + sum[x << 1 | 1];
}
inline void build(int l, int r, int x) {
if (l == r) {
sum[x] = a[l] - a[l - 1];
return;
}
int mid = l + r >> 1;
build(l, mid, x << 1);
build(mid + 1, r, x << 1 | 1);
pushup(x);
}
inline void pushdown(int l, int r, int x) {
if (lazy[x]) {
int mid = l + r >> 1;
lazy[x << 1] += lazy[x];
sum[x << 1] += (mid - l + 1) * lazy[x];
lazy[x << 1 | 1] += lazy[x];
sum[x << 1 | 1] += (r - mid) * lazy[x];
lazy[x] = 0;
}
}
inline void update(int l, int r, int x, int ql, int qr, ll val) {
if (l >= ql && r <= qr) {
lazy[x] += val;
sum[x] += val * (r - l + 1);
return;
}
pushdown(l, r, x);
int mid = l + r >> 1;
if (ql <= mid) update(l, mid, x << 1, ql, qr, val);
if (qr > mid) update(mid + 1, r, x << 1 | 1, ql, qr, val);
pushup(x);
}
inline ll query(int l, int r, int x, int ql, int qr) {
int mid = l + r >> 1;
if (l >= ql && r <= qr) {
return sum[x];
}
pushdown(l, r, x);
ll res = 0;
if (ql <= mid) res += query(l, mid, x << 1, ql, qr);
if (qr > mid) res += query(mid + 1, r, x << 1 | 1, ql, qr);
return res;
}
inline void solve() {
REP (i, 1, n + 1) {
cin >> a[i];
}
ll res = 0;
build(1, n, 1);
RREP (i, n, 1) {
ll num = k;
if (i <= k) num = i;
ll now = query(1, n, 1, 1, i);
ll sub = max(0ll, (now + num - 1) / num);
res += sub;
int front = i - k + 1;
if (front <= 0) front = 1;
update(1, n, 1, front, i, -sub);
}
cout << res << endl;
}
signed main() {
init();
cin >> n >> k;
solve();
return 0;
}
|