Codeforces 2110C Racing 题解 [ 黄 ] [ 构造 ] [ 栈 ] [ 贪心 ]

Racing:你怎么知道这个唐题卡了我 20min???

注意到高度单调不降相邻两个数最多差 \(1\) 的性质,不难发现合法的高度上下界 \(l_i,r_i\) 实际上是单调不降的。于是可以前缀后缀扫一遍求出这个合法上下界,当合法上界小于下界的时候直接返回无解即可。

如果无需构造方案,直接维护两个合法高度指针即可。

但此题需要给出详细方案,于是考虑调整法。注意到只有上下界两个限制,因此我们先尽可能地满足不超过上界的限制,即对于每个位置尽可能地赋 \(0\);在对于无法满足下界的位置时,对曾经赋 \(0\) 的位置进行调整即可。因为一个位置赋 \(1\) 会导致后缀全部加 \(1\),为了影响尽可能少的位置,需要贪心地从后往前\(1\),否则一定不优。这个操作可以利用栈来维护。

构造完方案后,再判断一遍调整之后方案合不合法即可。

时间复杂度 \(O(n)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=200005;
int n,d[N],l[N],r[N],h[N];
void solve()
{
    stack<int>stk;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>d[i];
    for(int i=1;i<=n;i++)
        cin>>l[i]>>r[i];
    for(int i=2;i<=n;i++)
        l[i]=max(l[i],l[i-1]);
    for(int i=n-1;i>=1;i--)
        r[i]=min(r[i],r[i+1]);
    memset(h,0,sizeof(h));
    int lx=0;
    for(int i=1;i<=n;i++)
    {
        if(d[i]==1)
        {
            lx++;
            h[i]=1;
        }
        else if(d[i]==-1)
            stk.push(i);
        while(!stk.empty()&&lx<l[i])
        {
            h[stk.top()]=1;
            stk.pop();
            lx++;
        }
        if(lx<l[i]||l[i]>r[i])
        {
            cout<<"-1\n";
            return;
        }
    }
    int cur=0;
    for(int i=1;i<=n;i++)
    {
        cur+=h[i];
        if(cur<l[i]||cur>r[i])
        {
            cout<<"-1\n";
            return;            
        }
    }
    for(int i=1;i<=n;i++)
        cout<<h[i]<<" ";
    cout<<'\n';
}
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    while(t--)solve();
    return 0;
}
posted @ 2025-05-28 23:45  KS_Fszha  阅读(50)  评论(0)    收藏  举报