📜  门|门CS 2011 |问题 33(1)

📅  最后修改于: 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页面查看参考代码。