1 条题解

  • 0
    @ 2025-7-13 17:51:59

    O(NlogN)O(NlogN) 前缀和,二分

    考虑每个茶会被哪些人喝

    对于第 ii 个茶,第一轮会被第 ii 个人喝,第二轮会被第 i+1i + 1 个人喝,第三轮... 直到茶被喝完或第 nn 个人喝过。

    结论:第 ii 个茶会被区间 [i,l][i,l] 的人喝,其中 llj=ilb[j]a[i]\sum_{j = i}^{l}{b[j]} \geq a[i] 的最小值.

    那么 ll 的求法也非常简单,可以用二分。

    此时 [i,l1][i,l - 1] 的人喝的值为 bb ,第 ll 个人喝的值为剩下的部分。

    可以用差分数组存储前者区间的部分,后者单独用数组存储。 最后统计答案即可。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<LL, LL> PII;
    
    #define x first
    #define y second
    
    const int N = 2e5 + 10, mod = 1e9 + 7;
    
    int a[N], b[N];
    LL sum[N];
    LL cnt[N], d[N]; // 喝b[i]的次数,a剩余的量
    
    void solve()
    {
        int n;
        cin >> n;
        for(int i = 1; i <= n; i ++) cnt[i] = d[i] = 0;
        for(int i = 1; i <= n; i ++) cin >> a[i];
        for(int i = 1; i <= n; i ++) cin >> b[i];
        
        for(int i = 1; i <= n; i ++)
            sum[i] = sum[i - 1] + b[i];
            
            
        for(int i = 1; i <= n; i ++)
        {
            if(b[i] >= a[i])
            {
                d[i] += a[i];
                continue;
            }
            
            int l = i, r = n; // <= a[i]的最大下标
            while(l < r)
            {
                int mid = l + r + 1 >> 1;
                if(sum[mid] - sum[i - 1] <= a[i]) l = mid;
                else r = mid - 1;
            }
            
            cnt[i] ++, cnt[l + 1] --;
            d[l + 1] += a[i] - sum[l] + sum[i - 1];
        }
        
        for(int i = 1; i <= n; i ++) 
        {
            cnt[i] += cnt[i - 1];
            cout << cnt[i] * b[i] + d[i] << ' ';
        }
        cout << endl;
    }
    
    int main()
    {
        int t = 1;
        scanf("%d", &t);
        while(t --)
            solve();
    }
    
    • 1

    信息

    ID
    197
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    12
    已通过
    4
    上传者