【CF5E Bindian Signalizing】题解

题目链接

题目

Everyone knows that long ago on the territory of present-day Berland there lived Bindian tribes. Their capital was surrounded by n n n hills, forming a circle. On each hill there was a watchman, who watched the neighbourhood day and night.

In case of any danger the watchman could make a fire on the hill. One watchman could see the signal of another watchman, if on the circle arc connecting the two hills there was no hill higher than any of the two. As for any two hills there are two different circle arcs connecting them, the signal was seen if the above mentioned condition was satisfied on at least one of the arcs. For example, for any two neighbouring watchmen it is true that the signal of one will be seen by the other.

An important characteristics of this watch system was the amount of pairs of watchmen able to see each other's signals. You are to find this amount by the given heights of the hills.

思路

首先,我们先把相邻且相同的合并,合并过程中统计这两个相邻的代价。

然后,我们把所有山峰放到一个小根堆里。

每次取出优先队列最小的那个元素,也就是当前最矮的山峰,然后统计和相邻的代价。

统计后删去这个山峰,然后判断如果左右的山峰相同则合并。

这个过程可以用链表辅助实现。

总结

这道题我个人感觉不难,但题解看了一圈基本上都在用单调栈+dp。

我认为这题和CSPJ2021T4有异曲同工之妙,其核心都是链表。

同时这题在推性质的时候如果从小的考虑,就发现只会对相邻的产生影响,固可以用优先队列来时现。

Code

// Problem: CF5E Bindian Signalizing
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF5E
// Memory Limit: 250 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 1000010
struct node
{
	int x, id; 
	bool operator <(const node &A) const
	{
		return x>A.x; 
	}
}t; 
struct Node
{
	int x, y, z, front, rear; 
}a[N]; 
int n, m, i, j, k; 
int lst, nxt, ans; 
priority_queue<node>q; 

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	n=read(); 
	for(i=1; i<=n; ++i) a[i].x=read(), a[i].y=1; 
	for(i=1; i<=n; ++i)
	{
		a[i].front=i-1; 
		a[i].rear=i+1; 
	}
	a[1].front=n; a[n].rear=1; 
	for(i=1; i<=n; ++i)
	{
		j=a[i].front; 
		// printf("%lld %lld\n", i, j); 
		if(a[i].x==a[j].x&&i!=j&&a[j].z==0&&a[i].z==0)
		{
			ans+=a[i].y*a[j].y; 
			a[i].y+=a[j].y; 
			// printf("a[%lld].y=%lld\n", i, a[i].y); 
			a[a[j].front].rear=i; 
			a[i].front=a[j].front;  
			a[j].z=1; 
		}
		// printf("%lld\n", ans); 
	}
	for(i=1; i<=n; ++i)
	{
		if(a[i].z) continue; 
		t.id=i; 
		t.x=a[i].x; 
		q.push(t); 
	}
	// printf("%lld\n", ans); 
	while(!q.empty())
	{
		// printf("%lld\n", ans); 
		t=q.top(); q.pop(); 
		i=t.id; 
		if(a[i].z) continue; 
		if(a[i].front==i) continue; 
		lst=a[i].front; nxt=a[i].rear; 
		ans+=a[i].y*2;
		// printf("a[%lld]=%lld\n", i, a[i].y); 
		a[i].z=1; 
		a[lst].rear=nxt; 
		a[nxt].front=lst; 
		if(lst==nxt) 
		{
			if(a[lst].y==1) ans-=a[i].y; 
			continue; 
		}
		if(a[lst].x==a[nxt].x)
		{
			// printf("> %lld\n", ans); 
			ans+=a[lst].y*a[nxt].y; 
			// printf("%lld %lld\n", lst, nxt); 
			// printf("> %lld %lld %lld\n", a[lst].y, a[nxt].y, ans); 
			a[lst].y+=a[nxt].y; 
			a[a[nxt].rear].front=lst; 
			a[lst].rear=a[nxt].rear; 
			a[nxt].z=1; 
		}
	}
	printf("%lld", ans); 
	return 0; 
}

上一篇:快速幂 A^B Mod C


下一篇:Keepalived