zoukankan      html  css  js  c++  java
  • 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的斜率(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;
    }
    
  • 相关阅读:
    2019.1.5JavaScript
    SQL常用删改增语句
    PHP连接数据库
    PHP数组函数
    PHP字符串常用函数
    PHP 类型判断方法
    jQuery效果
    jQuery特性
    倒计时
    判断浏览器及其内核
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/12874837.html
Copyright © 2011-2022 走看看