CF1661 D. Progressions Covering (1900 线段树区间加等差数列)
https://codeforces.com/contest/1661/problem/D
题意: 给出初始全零的a数组,和b数组,每次操作可以选择完整的长度为k的一段加上1,2,3...k.问最学要多少次操作才能使所有ai都大于bi。
思路: 这里有一个比较强的限制:选择完整的长度k的一段修改,这就使得修改1的话必须选择[1, k],修改n的话必须选择[n - k + 1, n]。然后发现从后往前对于每个非0的bi,肯定把它当右边界修改最快。
所以总体思路就是:倒着扫一遍,考虑如何快速区间等差数列加:
- 操作有区间修改,单点查询。 使用线段树维护,让val值为等差数列首项,lazy为公差,这样分裂时候左区间继承val和lazy,右区间的首项 :tree[rt].val + tree[rt].lazy * ( mid - l + 1); 单点修改不需要考虑合并。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<int, int>
const int N = 3e5 + 5;
const int M = 1e7 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
ll a[N];
struct node {
ll val, lazy;
}tree[N << 2];
void push_down( int l, int r, int rt ) {
if(!tree[rt].val && !tree[rt].lazy) return;
int mid = l + r >> 1;
tree[rt << 1].val += tree[rt].val;
tree[rt << 1 | 1].val += tree[rt].val + tree[rt].lazy * ( mid - l + 1);
tree[rt << 1].lazy += tree[rt].lazy;
tree[rt << 1 | 1].lazy += tree[rt].lazy;
tree[rt].val = tree[rt].lazy = 0;
}
void modify ( int a, int b, ll st, ll d, int l, int r, int rt ) {
if( r < a || l > b) return;
if( l >= a && r <= b) {
tree[rt].val += st + d * (l - a);
tree[rt].lazy += d;
return;
}
int mid = l + r >> 1;
push_down(l, r, rt);
modify(a, b, st, d, l, mid, rt << 1);
modify(a, b, st, d, mid + 1, r, rt << 1 | 1);
}
int query( int pos, int l, int r, int rt ) {
if(l == r) return tree[rt].val;
push_down( l, r, rt );
int mid = l + r >> 1;
if(pos <= mid) return query( pos, l, mid, rt << 1 );
else return query(pos, mid + 1, r, rt << 1 | 1);
}
int main () {
IOS
int n, k; cin >> n >> k;
for ( int i = 1; i <= n; ++ i ) cin >> a[i];
ll ans = 0;
for ( int i = n; i >= 1; -- i ) {
ll val = query(i, 1, n, 1);
if( val >= a[i] ) continue;
if(i - k + 1 >= 1) {
ll mul = (a[i] - val) / k + ((a[i] - val) % k != 0);
modify(i - k + 1, i, mul, mul, 1, n, 1);
ans += mul;
} else {
ll mul = (a[i] - val) / i + ((a[i] - val) % i != 0);
modify(1, i, mul, mul, 1, n, 1);
ans += mul;
}
}
cout << ans << endl;
}