HNOI2019 鱼

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的斜率\(\pm\frac \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\n",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\n",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\n",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\n",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\n\n\n\n",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;
}
posted @ 2020-05-12 11:00  lcyfrog  阅读(178)  评论(0编辑  收藏  举报