P6149 [USACO20FEB] Triangles S题解

P6149 USACO20FEB Triangles S

USACO20FEB Triangles S

题目描述

Farmer John 想要给他的奶牛们建造一个三角形牧场。

有 N N N( 3 ≤ N ≤ 1 0 5 3\leq N\leq 10^5 3≤N≤105)个栅栏柱子分别位于农场的二维平面上不同的点 ( X 1 , Y 1 ) ... ( X N , Y N ) (X_1,Y_1)\ldots (X_N,Y_N) (X1,Y1)...(XN,YN)。他可以选择其中三个点组成三角形牧场,只要三角形有一条边与 x x x 轴平行,且有另一条边与 y y y 轴平行。

FJ 可以组成的所有可能的牧场的面积之和等于多少?

输入格式

第一行包含 N N N。

以下 N N N 行每行包含两个整数 X i X_i Xi 和 Y i Y_i Yi,均在范围 − 1 0 4 ... 1 0 4 −10^4\ldots 10^4 −104...104 之内,描述一个栅栏柱子的位置。

输出格式

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

样例 #1

样例输入 #1

复制代码
4
0 0
0 1
1 0
1 2

样例输出 #1

复制代码
3

提示

样例解释:

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

子任务:
  • 测试点 2 2 2 满足 N = 200 N=200 N=200。
  • 测试点 3 3 3- 4 4 4 满足 N ≤ 5000 N\leq 5000 N≤5000。
  • 测试点 5 5 5- 10 10 10 没有额外限制。

题解

首先考虑只统计直角顶点在右上角的三角形。

对于每个点,它的贡献是它正左边的点到该点的长度和乘以正下方的点到该点的长度和。

对于所有的点,按照 X X X为第一关键字, Y Y Y为第二关键字排序。

对于左边的点,开一个桶统计总数。对于下边的点同理。

那么对于直角顶点不在右上角的三角形呢?

我们只用将所有的点绕原点旋转 90 ° 90° 90°后再统计即可,总共旋转三次

时间复杂度 O ( N ) O(N) O(N)

AC代码

cpp 复制代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n;
struct node{
	int x,y;
	bool operator<(const node o)const{
		if(x^o.x)return x<o.x;
		return y<o.y;
	}
}a[N];
typedef long long ll;
ll ans=0;const ll P = 1000000007LL;const int bas = 10007;
ll sum[N],cnt[N];
void solve(){
	sort(a+1,a+n+1);
	memset(sum,0,sizeof(sum));
	memset(cnt,0,sizeof(cnt));
	ll now = 0,tot = 0 ;
	rep( i , 1 , n ){
		if(a[i].x != a[i-1].x )now = 0 ,tot = 0 ;
		ans=(ans + ( a[i].x * cnt[a[i].y + bas] - sum[ a[i].y + bas ] )
		    % P * ( a[i].y * tot - now ) % P ) % P;
		tot++;now=(now+a[i].y)%P;
		cnt[a[i].y+bas]++;
		sum[a[i].y+bas]=(a[i].x+sum[a[i].y+bas])%P;
	}
}
void rev(){
	rep(i,1,n){
		int x=a[i].x,y=a[i].y;
		a[i].x=y;a[i].y=-x;
	}
}
int main(int argc, const char * argv[]){
	scanf("%d",&n);
	rep(i,1,n)scanf("%d%d",&a[i].x,&a[i].y);
	rep(i,0,3){
		solve();rev();
	}
	printf("%lld\n",ans);
	return 0;
}
//Written by Kevin ☑
相关推荐
郝学胜-神的一滴3 小时前
AI 编程智能体 16:从零基础搭建到精细化优化
人工智能·python·算法·语言模型·langchain·pip
喜欢打篮球的普通人3 小时前
AI 编译器内存分配算法:从静态/动态划分到内存复用
人工智能·算法
mjhcsp4 小时前
Code date creation v8.0 竞赛数据生成与对拍实战指南
算法·ai·深度优先·cdc
小郎君6584 小时前
keep-alive 页面怎么“真刷新”?别改外层 key——一个 refreshVersion 的完整实现
vue.js·算法
瑶池酒剑仙5 小时前
C++变量初始化五法完全指南:默认/拷贝/直接/列表/值初始化与窄化转换陷阱(青云之志)
c语言·开发语言·数据结构·c++·算法·visual studio
用户238003099455 小时前
从零开始实现扫雷游戏(C 语言控制台版)
算法
国科安芯5 小时前
星上计算的第一道防线:低轨遥感卫星载荷处理链中的AS32S601型抗辐射MCU—— 面向高分辨率成像与在轨智能处理的场景化综述
大数据·网络·人工智能·单片机·算法·低轨卫星·抗辐射
thusloop5 小时前
零门槛接入 GPT-6-astra 与 claude-opus-5-5,三大场景实战指南
python·gpt·算法·agent·claude·codex
瓦瓦gogo5 小时前
学回溯算法时,我先弄明白了怎么“退回来”
算法
Lzg_na6 小时前
堆和堆排序
算法