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;
}

浙公网安备 33010602011771号