P8094 [USACO22JAN] Cow Frisbee S

Link\text{Link}

考场上唯一会的题(wtcl。

题意

一个 1n1\sim n 的排列 h1,h2,,hnh_1,h_2,…,h_n,求 i=1nj=i+1n[maxk=i+1j1hk<min(hi,hj)]\sum^n_{i=1}\sum^n_{j=i+1}[\max^{j-1}_ {k=i+1}h_k<\min(h_i,h_j)]

分析

hi=min(hi,hj)h_i=\min(h_i,h_j),则满足要求的 hjh_j 最多只有两个:hih_i 左边第一个满足 hj>hih_j>h_i 的数和 hih_i 右边第一个满足 hj>hih_j>h_i 的数。

以下图的 h3=5h_3=5 为例:

对于 h3h_3 左边的数,h1=8h_1=8 是第一个比它大的,因此中间的数都比他们小,必然满足 maxk=i+1j1hk<hi<hj\max^{j-1}_ {k=i+1}h_k<h_i<h_j

对于 h3h_3 右边的数,h6=6h_6=6 是第一个比它大的,因此中间的数都比他们小,必然满足 maxk=i+1j1hk<hi<hj\max^{j-1}_ {k=i+1}h_k<h_i<h_j。但是 h6h_6 后面有 h8>h6>h3h_8>h_6>h_3,那么 h8h_8 能不能算入答案呢?显然不能,因为 maxk=i+1j1hk=h6>h3\max^{j-1}_ {k=i+1}h_k=h_6>h_3

因为 hihjh_i\neq h_j,所以每个数对 (i,j)(i,j) 只会从较小的 hih_i 出发计算的方法计算一次,因此答案不重不漏。

那么如何计算左/右边第一个比 hih_i 大的数呢,开个小根堆,统计即可,时间复杂度 O(nlogn)O(n\log n)

但好像用栈可以 O(n)O(n)?管他呢,能过就行。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=3e5+10;
int n,h[N],d[N];
priority_queue<int>q;
ll ans;
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		h[i]=read();
		d[h[i]]=i;
		while(q.size()&&-q.top()<h[i]){
			ans+=abs(i-d[-q.top()])+1;
			q.pop();
		}
		q.push(-h[i]);
	}
	while(q.size())
		q.pop();
	for(int i=n;i;i--){
		while(q.size()&&-q.top()<h[i]){
			ans+=abs(i-d[-q.top()])+1;
			q.pop();
		}
		q.push(-h[i]);
	}
	write(ans);
	return 0;
}
posted @ 2022-02-05 12:16  luckydrawbox  阅读(30)  评论(0)    收藏  举报  来源