[POI2008]TRO-Triangles
X.[POI2008]TRO-Triangles
本题介绍两种做法。
一种是我自己的做法:
考虑某,
于是我们考虑固定某个,这时就可以令,这样我们只需要求出所有的即可。
如果它没有前缀和,我们完全可以直接乘法分配律掉;但是套上绝对值,咋办呢?
我们考虑到,设表示与的夹角(其中在的逆时针方向),则只有在时,绝对值内的东西才为正;而,其中指的辐角。于是我们将所有东西依照辐角排序,并且用一个two-pointers统计对于某个,所有有的之和。然后直接叉积在一起即可。
最终答案要除以,因为每个三角形都在三个顶点被统计了三次,并且一开始的式子是。
复杂度。鉴于此题极度卡常,最后挂掉了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
const double pi=acos(-1);
struct Vector{
int x,y;
Vector(int X=0,int Y=0){x=X,y=Y;}
friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
void operator +=(const Vector &v){x+=v.x,y+=v.y;}
friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
void operator -=(const Vector &v){x-=v.x,y-=v.y;}
friend Vector operator *(const Vector &u,const int &v){return Vector(u.x*v,u.y*v);}
friend Vector operator /(const Vector &u,const int &v){return Vector(u.x/v,u.y/v);}
friend ll operator &(const Vector &u,const Vector &v){return 1ll*u.x*v.y-1ll*u.y*v.x;}//cross times
friend ll operator |(const Vector &u,const Vector &v){return 1ll*u.x*v.x+1ll*u.y*v.y;}//point times
double operator !()const{return atan2(y,x);}//the angle of a vector
friend bool operator <(const Vector &u,const Vector &v){return !u<!v;}
void read(){scanf("%d%d",&x,&y);}
void print(){printf("(%d,%d)",x,y);}
}p[3010],q[3010];
typedef Vector Point;
ll res;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)p[i].read();
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)q[j]=p[j]-p[i];
sort(q,q+n);
m=1;for(int j=1;j<n;j++)if((q[j]&q[m-1])||(q[j]|q[m-1])<0)q[m++]=q[j];else q[m-1]+=q[j];
// for(int j=0;j<m;j++)q[j].print();puts("");
Vector sum;
int len=0;
for(int j=0,k=0;j<m;j++){
if(!len)sum=sum+q[k],len++,k=(k+1)%m;
for(;len<m&&(q[j]&q[k])>0;k=(k+1)%m)sum+=q[k],len++;
// printf("%lld\n",q[j]&sum);
res+=q[j]∑
sum-=q[j],len--;
}
}
res/=3;
printf("%lld.%d\n",res>>1,(res&1)?5:0);
return 0;
}
一种是正解做法。
我们考虑对于每个三角形,我们只在它左下方的节点统计一次。方法很简单,一开始将所有顶点先按照为第一关键字,为第二关键字排一次序,之后每次只需要统计后缀即可。
然后,每个节点所统计的所有东西,都在其右侧;故只需要进行一遍极角排序,对于一个节点,它后方的所有东西,都有叉积。所有统计后缀和并进行叉积即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
const double pi=acos(-1);
struct Vector{
int x,y;
Vector(int X=0,int Y=0){x=X,y=Y;}
friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
void operator +=(const Vector &v){x+=v.x,y+=v.y;}
friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
void operator -=(const Vector &v){x-=v.x,y-=v.y;}
friend Vector operator *(const Vector &u,const int &v){return Vector(u.x*v,u.y*v);}
friend Vector operator /(const Vector &u,const int &v){return Vector(u.x/v,u.y/v);}
friend ll operator &(const Vector &u,const Vector &v){return 1ll*u.x*v.y-1ll*u.y*v.x;}//cross times
friend ll operator |(const Vector &u,const Vector &v){return 1ll*u.x*v.x+1ll*u.y*v.y;}//point times
friend bool operator <(const Vector &u,const Vector &v){return (u&v)>0;}
void read(){scanf("%d%d",&x,&y);}
void print(){printf("(%d,%d)",x,y);}
}p[3010],q[3010];
typedef Vector Point;
ll res;
bool cmp(const Vector &u,const Vector &v){return (u.x==v.x)?u.y<v.y:u.x<v.x;}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)p[i].read();
sort(p,p+n,cmp);
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++)q[j]=p[j]-p[i];
sort(q+i+1,q+n);
for(int k=n-1;k>i;k--)res+=(q[k]&q[k+1]),q[k]+=q[k+1];
}
printf("%lld.%d\n",res>>1,(res&1)?5:0);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?