HNOI2019 鱼
加起来写了一天,最后6.8k代码过的
我的分数:10-20-30-20-40-50-60-...-60-80-100
考场上就写暴力跑路了。不过做出来还是挺有成就感的,快乐就vans了
显然,知道AD那么BC和EF可以分开算。
考虑枚举AD这条线,那么斜率和截距相同的线我们可以一起枚举(用vector)。并且注意到每条线对应的中垂线只有一条,我们可以用hash表来找。考虑把中垂线为AD的线(BC)对应到这条线上变成一个点,加入点集,权值为0,AD这条线上的点也加入到点集,权值为1,并且按x和y排好序,那么我们要找的就是在每个1点之前的权值分别为10这样的点对个数再乘上以这个点作为D点的EF的答案。
至于10的点对个数怎么算,定义(cnt1)是1的个数,(cnt0)是10这样的点对个数。每遇到0就把cnt+=cnt1,遇到1则cnt1++,那么对于每个1之前的10点对个数就是cnt。
怎么计算EF呢?我们是知道AD这条线的,那么EF对于D的极角就在一个长度为(pi)的区间里(AD的斜率(pmfrac pi 2)。我们把每个D点的这些需要统计的区间离线下来,然后排好序单调队列即可。这里面还要用hash表或者unordered_map来存DE(DF)的长度,贡献维护每个长度出现次数x的(C(x,2))之和,再乘上离线下来的点对个数。
注意我们按x和y排序,从右往左和从上往下的鱼不会被算到,还要把每个点横纵坐标取相反数再算一次。
我WA这么多次主要是精度问题,要多调参,斜率和截距可以用4个longlong来存(分子和分母)。特别注意斜率不存在的情况。
#include<bits/stdc++.h>
#define db long double
#define ll long long
#define pr pair<ll,ll>
#define pii pair<int,int>
#define pdl pair<long double,ll>
#define fi first
#define se second
#define mpr make_pair
#define ull unsigned long long
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define ROF(i,a,b) for(int i=a;i>=b;++i)
using namespace std;
ll read(){
ll x=0,pos=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return pos?x:-x;
}
int n;
const int N =1021;
struct point{
ll x,y;
point(ll x=0,ll y=0):x(x),y(y){}
point operator -(point b){
return point(x-b.x,y-b.y);
}
ll dis(){
return x*x+y*y;
}
}p[N];
struct EFP{
long double the;ll res;
int operator < (EFP b){
return the<b.the;
}
}ef[N][N];
int cnt=0;
vector<pii>vec[1000021];
ll gcd(ll a,ll b){
return !b?a:gcd(b,a%b);
}
int vis[1021];
const ll mod1 = 998244353,mod2=1e9+7;
const ll base = 1331,ba2=31;
struct line{
ll kx,ky,bx,by;
line(ll kx=0,ll ky=0,ll bx=0,ll by=0):kx(kx),ky(ky),bx(bx),by(by){}
int hash(){
ll h1=(((kx*base%mod1+ky)%mod1*base+bx)%mod1*base+by)%mod1;
ll h2=(((kx*ba2%mod2+ky)%mod2*ba2+bx)%mod2*ba2+by)%mod2;
return (h2*100000000ll+h1)%4000000;
}
int operator == (line bb){
return kx==bb.kx&&ky==bb.ky&&bx==bb.bx&&by==bb.by;
}
};
struct NODE{
int nex,cnt;line w;
};
struct hash_table{
NODE edge[4000021];
int head[4000021],tup=0,nh[4000021],nt=0;
void insert(line &now,int wi){
int u=now.hash();
if(!head[u]) nh[++nt]=u;
edge[++tup].w=now;
edge[tup].cnt=wi;
edge[tup].nex=head[u];
head[u]=tup;
}
int count(line &now){
int u=now.hash();
for(int i=head[u];i;i=edge[i].nex){
if(edge[i].w==now) return edge[i].cnt;
}
return -1;
}
void clear(){
for(int i=1;i<=tup;i++){
edge[i].nex=edge[i].cnt=0;edge[i].w=line(0,0,0,0);
}tup=0;
for(int i=1;i<=nt;i++){
head[nh[i]]=0;nh[i]=0;
}nt=0;
}
}d,zd;
int cntz=0;vector<pii>vecz[1000021];
inline void getmin(ll &x,ll &y){
if(x<0&&y<0) x*=-1ll,y*=-1ll;
if(y>0&&x<0) y*=-1ll,x*=-1ll;
if(x==0&&y==0){
return;
}else if(y==0) return x=1,void();
else if(x==0) return y=1,void();
ll g=gcd(abs(y),abs(x));y/=g,x/=g;
}
inline line getline(ll dx,ll dy,ll sx,ll sy){
getmin(dx,dy);
ll by=sy*dx-sx*dy,bx=dx;
getmin(bx,by);
if(dx==0) by=sx;
return line(dx,dy,bx,by);
}
struct node{
db x,y;int col,id;
node(db x=0,db y=0,int col=0,int id=0):x(x),y(y),col(col),id(id){}
}q[1021];int top=0;
node get_ty(int i,line now){
if(now.kx==0){
return node(now.by,p[i].y,0,0);
}
long double k=(long double)(now.ky)/now.kx,b=(long double)(now.by)/now.bx;
long double x0=p[i].x,y0=p[i].y;
long double x=(x0+y0*k-b*k)/(k*k+1.0),y=k*x+b;
return node(x,y,0,0);
}
line getiv(line now){
swap(now.kx,now.ky);now.ky*=-1;
if(now.ky>0&&now.kx<0) now.ky*=-1ll,now.kx*=-1ll;
if(now.kx==0&&now.ky==0){
return now;
}else if(now.ky==0) now.kx=1;
else if(now.kx==0) return now.ky=1;
return now;
}
const long double eps = 1e-2;
int cmp0(node a,node b){
return fabs(a.x-b.x)<eps?fabs(a.y-b.y)<eps?a.col>b.col:a.y<b.y:a.x<b.x;
}
int cmp1(node a,node b){
return fabs(a.x-b.x)<eps?fabs(a.y-b.y)<eps?a.col<b.col:a.y>b.y:a.x<b.x;
}
vector<pdl> c[1021];
ll ans=0;
inline void out(ll a){
if(a>9 )out(a/10);
putchar(a%10+'0');
}
void solve(int ord){
FOR(i,1,n){
FOR(j,1,n){
if(i==j) continue;
point tmp=(p[j]-p[i]);
ef[i][j-(j>i)].the=atan2(tmp.y,tmp.x);
ef[i][j-(j>i)].res=tmp.dis();
}
sort(ef[i]+1,ef[i]+n);
}
FOR(i,1,n){
FOR(j,i+1,n){
if(i==j) continue;
ll dy=(p[i].y-p[j].y),dx=(p[i].x-p[j].x);
line now=getline(dx,dy,p[i].x,p[i].y);
int nn=d.count(now);
if(nn!=-1) vec[nn].push_back(mpr(i,j));
else d.insert(now,++cnt),vec[cnt].push_back(mpr(i,j));
now.bx=(p[i].x+p[j].x)/2,now.by=(p[i].y+p[j].y)/2;
now=getline(-now.ky,now.kx,now.bx,now.by);
nn=zd.count(now);
if(nn!=-1) vecz[nn].push_back(mpr(i,j));
else zd.insert(now,++cntz),vecz[cntz].push_back(mpr(i,j));
}
}
for(int i=1;i<=cnt;i++){
int d1=vec[i][0].fi,d2=vec[i][0].se;
ll dy=(p[d1].y-p[d2].y),dx=(p[d1].x-p[d2].x);
line now=getline(dx,dy,p[d1].x,p[d1].y);
top=0;
for(int j=0;j<vec[i].size();j++){
if(!vis[vec[i][j].fi]) vis[vec[i][j].fi]=1,q[++top]=node(p[vec[i][j].fi].x,p[vec[i][j].fi].y,1,vec[i][j].fi);
if(!vis[vec[i][j].se]) vis[vec[i][j].se]=1,q[++top]=node(p[vec[i][j].se].x,p[vec[i][j].se].y,1,vec[i][j].se);
}
int iv;
int kk=zd.count(now);
if(kk!=-1) iv=kk;
else{
for(int j=0;j<vec[i].size();j++){
vis[vec[i][j].fi]=0,vis[vec[i][j].se]=0;
}
continue;
}
for(int j=0;j<vecz[iv].size();j++){
if(!vis[vecz[iv][j].fi]) q[++top]=get_ty(vecz[iv][j].fi,now);
vis[vecz[iv][j].fi]=1,vis[vecz[iv][j].se]=1;
}
for(int j=0;j<vec[i].size();j++){
vis[vec[i][j].fi]=0,vis[vec[i][j].se]=0;
}
for(int j=0;j<vecz[iv].size();j++){
vis[vecz[iv][j].fi]=0,vis[vecz[iv][j].se]=0;
}
sort(q+1,q+top+1,ord?cmp1:cmp0);
ll cntt=0,cnt1=0,res=0;
db pre=-1;int samep=0;
for(int j=1;j<=top;j++){
if(now.kx!=0){
if(fabs(q[j].x-pre)<eps) samep+=q[j].col;
else pre=q[j].x,samep=q[j].col;
}else{
if(fabs(q[j].y-pre)<eps) samep+=q[j].col;
else pre=q[j].y,samep=q[j].col;
}
if(q[j].col==0) cntt+=cnt1-samep;
else{
cnt1++;
if(now.kx<0) now.kx*=-1,now.ky*=-1;
long double thi=atan2(now.ky,now.kx);
if(now.kx==0){
if(ord==0) thi=acos(-1)/2.0;
else thi=-acos(-1)/2.0;
}
if(cntt){
c[q[j].id].push_back(mpr(thi,cntt));
// printf("%d %d
",i,q[j].id);
}
}
}
}
for(int i=1;i<=n;i++){
sort(c[i].begin(),c[i].end());
long double lm,rm;
int l=1,r=0;
ll ri=0;unordered_map<ll,int>mp;
for(int j=0;j<c[i].size();j++){
lm=c[i][j].fi-acos(-1)/2.0,rm=c[i][j].fi+acos(-1)/2.0;
while(r+1<n&&ef[i][r+1].the<rm-1e-10){
r++;
if(mp.count(ef[i][r].res)){
ll x=mp[ef[i][r].res];ri-=x*(x-1)/2ll;ri+=(x+1)*(x)/2ll;
}
mp[ef[i][r].res]++;//if(i==4) //printf("%d %lld
",r,ri);
}
while(l<=r&&l<n&&ef[i][l].the<lm+1e-10){
ll x=mp[ef[i][l].res];ri-=x*(x-1)/2ll;ri+=(x-1)*(x-2)/2ll;
mp[ef[i][l++].res]--;//if(i==4) //printf("%d %lld
",l,ri);
}
if(!ri||!c[i][j].se) continue;
ans+=4ll*ri*c[i][j].se;//printf("now:%d lm:%lf rm:%lf l:%d r:%d re:%d add:%lld
",i,lm,rm,l,r,ri,4ll*ri*c[i][j].se);
}
c[i].clear();
}
for(int i=1;i<=cnt;i++){
vec[i].clear();
}cnt=0;
for(int i=1;i<=cntz;i++){
vecz[i].clear();
}cntz=0;memset(ef,0,sizeof ef);memset(q,0,sizeof(q));d.clear(),zd.clear();top=0;
//printf("%lld
",ans);
}
int main(){
n=read();
FOR(i,1,n){
p[i].x=read()*2ll,p[i].y=read()*2ll;
}
solve(0);
FOR(i,1,n){
p[i].x*=-1;p[i].y*=-1;
}
solve(0);
out(ans);
return 0;
}