本题的思路感觉没有那么难,但是最麻烦的是理解题目中的数学公式。在题目中r所需要满足的两个要求其实是A从i开始的累加和直到到达r的位置使小于等于k*c,到r+1的位置大于k*c。
那么我们可以计算A的前缀和,然后在使用upper_bound的时候将查找的值加上a[i-1],这样就实现了在i到最后的位置的前缀和的查找。
然后考虑题目中说的链接每次操作可以选择一个下标 让c对应下标的值加一。让c的值加一的话可能会使在这个下标下的r值增大,但绝对不会减小。所以我们想要max-min最小就需要去改变min的值。在这里使用一个优先队列去维护每个堆顶都是最小的B值。然后去改变这个下标下的c值重新计算r值。之后将得到的新数据维护最大最以及答案的值。
//那两个要求就相当于找最远的插入位置
//计算A的前缀和可以使用upper_bound来二分查找ri的值,由于c的增加不会让最大的B值变小,所以采用优先队列去实现一B的值为小根堆的优先队列。
//每次操作就从优先队列里面取出堆顶的元素,让其对应的C坐标加一重新计算

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int maxn = 2e5+10;
struct Node {
    int posi;
    int val;
    bool operator < (const Node &nd) const {
        return val>nd.val;
    }
};

int a[maxn], k[maxn], c[maxn];
int r[maxn];
priority_queue<Node> pq;

int rd() {
    int num=0, k = 1;
    char ch = getchar();
    while (ch=='-') {
        k = k^1;
        ch = getchar();
    }
    while (ch>='0'&&ch<='9') {
        num = num*10+(ch-'0');
        ch = getchar();
    }
    return num;
}

signed main() {
    int n, m;
    n = rd();m = rd();
    for (int i=1;i<=n;i++) {
        a[i] = rd();
        a[i] = a[i] + a[i-1];
    }
    for (int i=1;i<=n;i++) {
        k[i] = rd();
    }
    for (int i=1;i<=n;i++) {
        c[i] = rd();
    }
    int Max = INT_MIN;
    //开始初步计算r以及数组b的值。
    for (int i=1;i<=n;i++) {
        int pos = upper_bound(a+i, a+n+1, a[i-1]+k[i]*c[i])-a;
        r[i] = pos-1;
        pq.push({i, r[i]-i+1});
        Max = max(Max, r[i]-i+1);
    }
    int ans = Max - pq.top().val;
    //给了m次机会,每次都对对小的值进行操作,因为对最大的值进行操作只能变得更大没有意义。
    //因为情况并不单调,所以得在计算过程中进行记录更新
    while (m--) {
        Node nd = pq.top();
        int i = nd.posi;
        if (r[i]==n) continue;
        pq.pop();
        c[i]++;
        int pos = upper_bound(a+i, a+n+1, a[i-1]+k[i]*c[i])-a;
        r[i] = pos-1;
        pq.push({i, r[i]-i+1});Max = max(Max, r[i]-i+1);
        ans = min(ans, Max - pq.top().val);
    }
    cout<<ans;
    return 0;
}