2020寒假【gmoj2411】【Triangles】

题目描述

Farmer John 想要给他的奶牛们建造一个三角形牧场。有 N(3≤N≤10^5)个栅栏柱子分别位于农场的二维平面上不同的点 (X1,Y1)…(XN,YN)。他可以选择其中三个点组成三角形牧场,只要三角形有一条边与 x 轴平行,且有另一条边与 y 轴平行。
FJ 可以组成的所有可能的牧场的面积之和等于多少?

输入

第一行包含 N。
以下 N 行每行包含两个整数 Xi 和 Yi,均在范围 −104…104 之内,描述一个栅栏柱子的位置。

输出

由于面积之和不一定为整数且可能非常大,输出面积之和的两倍模 10^9+7 的余数。

样例输入

4
0 0
0 1
1 0
1 2

样例输出

3

数据范围限制

测试点 1-2 满足 N=200。
测试点 3-4 满足 N≤5000。
测试点 5-10 没有额外限制。

提示

栅栏木桩 (0,0)、(1,0) 和 (1,2) 组成了一个面积为 1 的三角形,(0,0)、(1,0) 和 (0,1) 组成了一个面积为 0.5 的三角形。所以答案为 2*(1+0.5)=3。

分析

现在这%%beginend大佬。
大佬教的神奇方法。就是把所有点的横纵坐标排序,然后做前缀和。算出每个点的s1和s2,所有s1和s2乘起来再累加就可以。
s1就是长。s2就是宽。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int mod=1000000007;
long long n,s[100001],s1[100001],s2[100001];
long long ans;
struct node
{
	int x,y,id;
}a[100001];
int cmp(node l,node r)
{
	return l.x<r.x||l.x==r.x&&l.y<r.y;
}
int cmp1(node l,node r)
{
	return l.y<r.y||l.y==r.y&&l.x<r.x;
}
int main()
{
	freopen("triangles.in","r",stdin);
	freopen("triangles.out","w",stdout); 
    cin>>n;
    for(register int i=1;i<=n;i++)
    {
    	cin>>a[i].x>>a[i].y;
    	a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		int j=i;
		while(j<n&&a[j+1].x==a[j].x) j++;
		s[i-1]=0;
		for(int k=i;k<=j;k++) s[k]=s[k-1]+a[k].y;
		for(int k=i;k<=j;k++)
		{
			s1[a[k].id]=s[j]-s[k]-(j-k)*a[k].y+(k-i)*a[k].y-(s[k-1]-s[i-1]);
		}
		i=j;
	}
	sort(a+1,a+n+1,cmp1); 
	for(int i=1;i<=n;i++)
	{
		int j=i;
		while(j<n&&a[j+1].y==a[j].y) j++;
		s[i-1]=0;
		for(int k=i;k<=j;k++) s[k]=s[k-1]+a[k].x;
		for(int k=i;k<=j;k++)
		{
			s2[a[k].id]=s[j]-s[k]-(j-k)*a[k].x+(k-i)*a[k].x-(s[k-1]-s[i-1]);
		}
		i=j;
	}
	for(int i=1;i<=n;i++)
	{
		ans+=(s1[i]*s2[i])%mod;
	}
	cout<<ans%mod;
	fclose(stdin);
	fclose(stdout);
    return 0;
}

大佬的脑回路有点清奇。。。

发布了110 篇原创文章 · 获赞 100 · 访问量 8001

猜你喜欢

转载自blog.csdn.net/dglyr/article/details/105678221
今日推荐