题意:有n重问题,难度i的题目个数为ai个,每套题目有k个题且题目难度必须连续,问最多可以有多少套题目
贪心,每次尽量选最靠前的连续区间,用线段树维护一下。
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long
const int maxm = 100005;
const int INF = 1e9 + 7;
struct node
{
int l, r, mi;
ll sum, lazy;
}tr[maxm * 8];
int a[maxm];
void make(int l, int r, int num)
{
tr[num].l = l, tr[num].r = r;
tr[num].lazy = 0;
if (l == r)
{
tr[num].mi = tr[num].sum = a[l];
return;
}
int mid = (l + r) / 2;
make(l, mid, num * 2);
make(mid + 1, r, num * 2 + 1);
tr[num].mi = min(tr[num * 2].mi, tr[num * 2 + 1].mi);
tr[num].sum = tr[num * 2].sum + tr[num * 2 + 1].sum;
}
void down(int x)
{
if (tr[x].l != tr[x].r)
tr[x * 2].lazy = tr[x * 2 + 1].lazy = tr[x].lazy;
tr[x].sum -= tr[x].lazy*(tr[x].r - tr[x].l + 1);
tr[x].mi -= tr[x].lazy, tr[x].lazy = 0;
}
void update(int l, int r, int num,int val)
{
if (tr[num].lazy) down(num);
if (tr[num].l >= l&&tr[num].r <= r)
{
tr[num].lazy = val;
down(num);
return;
}
int mid = (tr[num].l + tr[num].r) / 2;
if (mid >= r) update(l, r, num * 2, val);
else if (mid < l) update(l, r, num * 2 + 1, val);
else
{
update(l, mid, num * 2, val);
update(mid + 1, r, num * 2 + 1, val);
}
tr[num].sum = tr[num * 2].sum + tr[num * 2 + 1].sum;
tr[num].mi = min(tr[num * 2].mi, tr[num * 2 + 1].mi);
}
int query(int l, int r, int num)
{
if (tr[num].lazy) down(num);
if (tr[num].l >= l&&tr[num].r <= r)
return tr[num].mi;
int mid = (tr[num].l + tr[num].r) / 2, ans;
if (mid >= r)
ans = query(l, r, num * 2);
else if (mid < l)
ans = query(l, r, num * 2 + 1);
else ans = min(query(l, mid, num * 2), query(mid + 1, r, num * 2 + 1));
return ans;
}
int main()
{
int n, i, j, k, sum, t, now, ans;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &k);
for (i = 1;i <= n;i++)
scanf("%d", &a[i]);
make(1, n, 1);
i = 1, ans = 0;
while (1)
{
while (i + k - 1 <= n && (now = query(i, i + k - 1, 1)) <= 0)
i++;
if (i + k - 1 > n) break;
ans += now;
update(i, i + k - 1, 1, now);
}
printf("%d\n", ans);
}
return 0;
}