📅  最后修改于: 2023-12-03 14:58:37.302000             🧑  作者: Mango
在一条笔直的公路上,有n个点,每个点表示一个建筑物。这些建筑物都被一个高度相同的墙壁所包围,要么是红色的,要么是白色的。所有的建筑物都在墙壁内部。这些墙壁只能在建筑物之间的门处打开。问有多少个点能够看到至少一扇红门。若两个建筑物之间的门为红色,则可以看到红门,否则看不到。
具体问题请参见门|门CS 2011 |问题 33。
首先,我们可以画出建筑物和墙壁之间的关系,如下所示:
我们可以把一堵墙看成一条线段,这条线段可以分成若干段。对于这些线段,我们可以把它们按红门连在一起分成若干条红线段,再按白门连在一起分成若干条白线段。
如下图所示:
接下来我们考虑如何判断一个建筑物能否看到红门。
假设该建筑物所在的线段为白线段,它前面第一个红线段的右端点为$right$,后面第一个红线段的左端点为$left$,则该建筑物能够看到红门的充分必要条件是$right$和$left$垂直且该建筑物在$right$和$left$的连线下方。
如下图所示:
于是,我们可以枚举每个建筑物,对于每个白线段,找出前面第一个红线段和后面第一个红线段,判断该建筑物是否能够看到红门。若能够看到,则答案$+1$,否则继续枚举下一个建筑物。
最终求得的答案即为共有多少建筑物能够看到至少一扇红门。
代码如下:(注:为保证页码阅读体验,请在Luogu页面查看完整代码)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int ans;
int a[1005];
bool flag[1005];
int n;
bool check(int len1,int len2)
{
double A,B,C;
A=len2-len1,B=n-a[len1],C=len1*1.0*(n-len2);
return A*B>C;
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
char s[5];
scanf("%lld %s",&a[i],s);
if(s[0]=='R')flag[i]=true;
}
for(int i=1;i<=n;i++)
{
int r=-1,l=-1;
for(int j=i-1;j>=1;j--)
{
if(flag[j])r=j;
if(r!=-1&&a[r]>a[j]&&check(r,i))
{
ans++;
break;
}
}
for(int j=i+1;j<=n;j++)
{
if(flag[j])l=j;
if(l!=-1&&a[l]>a[j]&&check(i,l))
{
ans++;
break;
}
}
}
printf("%lld",ans);
return 0;
}
为保证阅读体验,请在Luogu页面查看参考代码。