题解:CF2089B2 Canteen (Hard Version)

· · 题解

题意描述

给定两个长度为 n 的整数序列 ab,保证 a 的元素和不超过 b 的元素和。需对 a 进行以下操作恰好 k 次:选择任意 a_i(满足 a_i > 0),使得 a_i=a_i-1

之后按以下操作循环处理:

每轮操作流程:

  1. 对每个位置 i,对 a_ib_i 同时减去 a_ib_i 的较小值。
  2. 构造新序列 c,其中 c_i = a_{(i-1) \bmod n}
  3. c 复制给 a

目标:找到经过恰好 k 次减操作后,使 a 全变为 0 所需的最少操作轮数。

解题思路

声明:以下序列下标均从 0 开始。

Easy Version

Hard Version

代码呈现

Easy Version

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

void solve()
{
    int n,k;
    cin>>n>>k;
    vector<int> a,b;
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        a.push_back(x);
    }
    for(int i=0;i<n;i++)
        a.push_back(a[i]);
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        b.push_back(x);
    }
    for(int i=0;i<n;i++)
        b.push_back(b[i]);
    stack<int> stk;
    int ans=0;
    for(int i=0;i<2*n;i++)
    {
        if(a[i])
            stk.push(i);
        while(!stk.empty()&&b[i])   
        {
            int now=stk.top();
            ans=max(ans,i-now+1);
            int minn=min(a[now],b[i]);
            b[i]-=minn,a[now]-=minn;
            if(i<n)
                b[i+n]-=minn,a[now+n]-=minn;
            if(a[now]==0)
                stk.pop();
        }
    }
    cout<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    while(T--)
        solve();
}

Hard Version

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int check(int n,int mid,vector<int> a,vector<int> b)
{
    stack<int> stk;
    int ans=0;
    for(int i=0;i<2*n;i++)
    {
        if(a[i])
            stk.push(i);
        while(!stk.empty()&&b[i])   
        {
            int now=stk.top();
            if(i-now+1>mid)
            {
                ans+=a[now];
                a[now]=0;
                if(now<n)
                    a[now+n]=0;
                stk.pop();
            }
            else
            {
                int minn=min(a[now],b[i]);
                b[i]-=minn,a[now]-=minn;
                if(i<n)
                    b[i+n]-=minn,a[now+n]-=minn;
                if(a[now]==0)
                    stk.pop();
            }
        }
    }
    return ans;
}
void solve()
{
    int n,k;
    cin>>n>>k;
    vector<int> a,b;
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        a.push_back(x);
    }
    for(int i=0;i<n;i++)
        a.push_back(a[i]);
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        b.push_back(x);
    }
    for(int i=0;i<n;i++)
        b.push_back(b[i]);
    int l=0,r=n;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(n,mid,a,b)>k)
            l=mid+1;
        else
            r=mid;
    }
    cout<<l<<endl;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    cin>>T;
    while(T--)
        solve();
}