其他分享
首页 > 其他分享> > USACO 2021 二月铂金组第一题 No Time To Dry

USACO 2021 二月铂金组第一题 No Time To Dry

作者:互联网

USACO 2021 February Contest, Platinum Problem 1. No Time To Cry

No Time To Dry

Bessie has recently received a painting set, and she wants to paint the long fence at one end of her pasture. The fence consists of N consecutive 1-meter segments (1≤N≤2⋅105). Bessie has N different colors available, which she labels with the letters 1 through N in increasing order of darkness (1 is a very light color, and N is very dark). She can therefore describe the desired color she wants to paint each fence segment as an array of N integers.
Initially, all fence segments are uncolored. Bessie can color any contiguous range of segments with a single color in a single brush stroke as long as she never paints a lighter color over a darker color (she can only paint darker colors over lighter colors).
For example, an initially uncolored segment of length four can be colored as follows:
0000 -> 1110 -> 1122 -> 1332
Unfortunately, Bessie doesn’t have time to waste watching paint dry. Thus, Bessie thinks she may need to leave some fence segments unpainted! Currently, she is considering Q candidate ranges (1≤Q≤2⋅105), each described by two integers (a,b) with 1≤a≤b≤N giving the indices of endpoints of the range a…b of segments to be painted.
For each candidate range, what is the minimum number of strokes needed to paint every fence segment inside the range with its desired color while leaving all fence segments outside the range uncolored? Note that Bessie does not actually do any painting during this process, so the answers for each candidate range are independent.

题目大意:Bessie要给长度为N(1 ≤ \leq ≤N ≤ 2 \leq2 ≤2 × \times × 105 )的栅栏染色,其中第i处的颜色为Ci。她每次可以给一个区间染成同一个颜色,但是她不能把更浅的颜色涂在更深的颜色上(Ci越小颜色越浅)。现在Bessie给出Q个询问(1 ≤ \leq ≤Q ≤ 2 \leq2 ≤2 × \times × 105 ),每次询问染色指定区间所需的最小染色次数。(每个询问独立,不会相互影响)。

题目思路:黄金组第二题的思路多多少少还是有帮助的。将这两道题的条件略作比较,我们便能发现,对于一个区间[a,b], 最少染色的次数为(b-a+1-f(a,b)),其中f(a,b)是在区间中满足下述条件的坐标对(l,r)的个数:l,r颜色相同,且在l,r之间没有比它们颜色更深的位置。

我们考虑离线处理询问:在保证右端点递增的前提下,我们可以用一个树状数组来存储坐标对个数的前缀和。我们只需要再维护一个颜色的堆,每次向右移动时删掉堆里比新坐标颜色浅的坐标。这样如果操作后堆顶是同一颜色,那么我们就找到了一个满足条件的坐标对,更新一下树状数组就可以了。维护树状数组复杂度为O(NlogN),询问总复杂度为O(Qlog(N)),算法总复杂度为O(N+Q)log(N)。

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
const int N=2e5+5;
int n,q,c[N],ans[N],a[N];
vector<pii> qq[N];
int query(int i) 
{
	int sum=0;
	for (;i;i-=i&-i)sum+=a[i];
	return sum;
}
int query(int l,int r){return query(r)-query(l-1);}
void update(int i){for(;i<=n;i+=i&-i)a[i]++;}
int main() {
	scanf("%d%d",&n,&q);
	for (int i=1;i<=n;i++)scanf("%d",&c[i]);
	for (int i=1;i<=q;i++)
    {
		int l,r;
        scanf("%d%d",&l,&r);
		qq[r].push_back({l,i});
	}
	vector<int>stk;
	for (int i=1;i<=n;i++)
    {
		while (!stk.empty()&&c[stk.back()]>c[i])stk.pop_back();//维护堆内颜色单调性
		if (!stk.empty()&&c[stk.back()]==c[i])//找到满足条件的坐标对
        {
			update(stk.back());
			stk.back()=i;//别忘了更新该颜色最新坐标
		}
        else stk.push_back(i);
		for (pii q: qq[i])ans[q.second]=i-q.first+1-query(q.first,i);//处理当前右端点所有询问
	}
	for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
    return 0;
}

标签:Dry,fence,No,int,USACO,stk,color,she,Bessie
来源: https://blog.csdn.net/Layomiiety/article/details/114530827