1 条题解

  • 0
    @ 2025-8-24 21:28:16

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ouuan
    如果奇迹有颜色的话,那么其中之一必是橙色的吧。

    搬运于2025-08-24 21:28:15,当前版本为作者最后更新于2018-07-19 14:19:01,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    本题要用到容斥原理+简单的计算几何

    最重要的一步在于如下图的容斥:

    其中,L,S,R分别代表三角形三条边的正下方的树的数量

    可以看出,三角形中树的数量就是|L+R-S|

    因此只要预处理出每条边正下方点的数量,再枚举每个三角形就可以算出答案了

    以下是各种细节,对于这道题来说,看懂上面的容斥之后建议自行完成所有细节,遇到问题再来看这篇题解:

    1.一个点在一条线段的正下方⇔横坐标在线段两端点之间&&该点在该线段所在直线的下方,而点在直线下方可以用两点式+点斜式判断。

    以点C和线段AB为例:

    直线AB解析式为y=(yA-yB)/(xA-xB)*(x-xA)+yA

    过C作AB平行线y=(yA-yB)/(xA-xB)*(x-xC)+yC

    比较C与AB的位置关系即比较yA-xA*(yA-yB)/(xA-xB)和yC-xC*(yA-yB)/(xA-xB)的大小关系

    2.每条线段的正下方应该不包括端点(否则边界会重合),并单独计算有点在公共端点下方的情况(否则边界会遗漏),然而若三角形有一边和y轴平行则不应计算有点在公共端点下方的情况,否则会将三角形的一个顶点算入答案中

    3.如右图所示,如果中间的点在另两个点所组成的线段的下方,中间的点会被算入,因此在预处理每条边正下方点的数量的同时也要预处理每个点和每条线段的位置关系(当然最后计算的时候再算一遍也行,毕竟是O(1)的也不用重复计算),如果中间的点在另两个点所组成的线段的下方要将答案加1

    最后代码如下:

    #include <iostream>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    int n,x[310],y[310],f[310][310],ans[310]; //f用来存每条边正下方点的数量,ans存答案
    bool down[310][310][310]; //存每条边和每个点的位置关系
    
    int main()
    {
        int i,j,k;
        long double kkk;
        
        cin>>n;
        
        for (i=1;i<=n;++i)
        {
            cin>>x[i]>>y[i];
        }
        
        for (i=1;i<n;++i) //预处理每条边正下方点的数量
        {
            for (j=i+1;j<=n;++j)
            {
                if (x[i]==x[j]) //记录有点在公共端点下方的情况,并且如果出现这种情况就不用判断这条线段和其它点的位置关系了
                {
                    if (y[i]<y[j])
                    {
                        ++f[0][j];
                    }
                    else
                    {
                        ++f[0][i];
                    }
                }
                else
                {
                    for (k=1;k<=n;++k)
                    {
                        if (i!=k&&j!=k&&x[k]>min(x[i],x[j])&&x[k]<max(x[i],x[j])) //判断点和线段的位置关系
                        {
                            kkk=1.0*(y[i]-y[j])/(x[i]-x[j]);
                            if (y[i]-kkk*x[i]>y[k]-kkk*x[k])
                            {
                                ++f[i][j];
                                down[i][j][k]=true;
                            }
                        }
                    }
                }
            }
        }
        
        for (i=1;i<=n-2;++i)
        {
            for (j=i+1;j<n;++j)
            {
                for (k=j+1;k<=n;++k)
                {
                    if (x[i]<=x[j]&&x[i]>=x[k]||x[i]>=x[j]&&x[i]<=x[k]) //找出横坐标在中间的点是哪个
                    {
                        if (x[i]==x[j]||x[i]==x[k]) //判断是否有边和y轴平行
                        {
                            ++ans[abs(f[i][j]+f[i][k]-f[j][k]+down[j][k][i])];
                        }
                        else
                        {
                            ++ans[abs(f[i][j]+f[i][k]+f[0][i]-f[j][k]+down[j][k][i])];
                        }
                    }
                    else if (x[j]<=x[i]&&x[j]>=x[k]||x[j]>=x[i]&&x[j]<=x[k])
                    {
                        if (x[i]==x[j]||x[j]==x[k])
                        {
                            ++ans[abs(f[i][j]+f[j][k]-f[i][k]+down[i][k][j])];
                        }
                        else
                        {
                            ++ans[abs(f[i][j]+f[j][k]+f[0][j]-f[i][k]+down[i][k][j])];
                        }
                    }
                    else
                    {
                        if (x[i]==x[k]||x[j]==x[k])
                        {
                            ++ans[abs(f[i][k]+f[j][k]-f[i][j]+down[i][j][k])];
                        }
                        else
                        {
                            ++ans[abs(f[i][k]+f[j][k]+f[0][k]-f[i][j]+down[i][j][k])];
                        }
                    }
                }
            }
        }
        
        for (i=0;i<n-2;++i)
        {
            cout<<ans[i]<<endl;
        } 
        
        return 0;
    }
    
    • 1

    信息

    ID
    693
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者