zoukankan      html  css  js  c++  java
  • LOJ#3054. 「HNOI 2019」鱼

    LOJ#3054. 「HNOI 2019」鱼

    https://loj.ac/problem/3054

    题意

    • 平面上有n个点,问能组成几个六个点的鱼。(n<=1000)

    分析

    鱼题,劲啊。

    • 容易想到先枚举这个(D),然后极角序排一下,我们枚举(A),对(B,E,F)分别统计。
    • 枚举(A)的过程中用一个指针维护(E,F)的范围,对答案贡献是一个(suminom{x}{2})的形式,容易维护。
    • 然后现在要求(B)的方案数,可以发现符合条件的(BC)一定满足线段(AD)垂直平分线段(BC)
    • 不难想到,预处理出来每条类似(BC)这样的线段,求出他们被垂直平分时那个直线的(a,b,c),同时因为(AD,BC)应有交,还需要存一个中点横坐标(X_{mid}),然后枚举(A)时用([L=X_A,R=X_D])算一下这之间有多少个点。然后可能有横坐标相等的情况,所以我又预处理的每条线段中点的纵坐标的信息。
    • 然后就做完了,注意一下精度。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <set>
    #include <vector>
    using namespace std;
    #define N 2050
    typedef double f2;
    typedef long long ll;
    const f2 eps=1e-10;
    const f2 pi=acos(-1);
    ll ans;
    int c[N],n,lb,len[N];
    ll rlen[N],V[N];
    ll pf(ll x) {return x*x;}
    ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
    struct Point {
    	ll x,y;
    	Point(){}
    	Point(ll x_,ll y_) {x=x_,y=y_;}
    	Point turn90(const Point &p) const {
    		Point re,t=*this-p;
    		re.x=-t.y;
    		re.y=t.x;
    		return re+p;
    	}
    	void prt() {
    		printf("%lld %lld
    ",x,y);
    	}
    	Point operator + (const Point &u) const {return Point(x+u.x,y+u.y);}
    	Point operator - (const Point &u) const {return Point(x-u.x,y-u.y);}
    	Point operator / (const ll &rate) const {return Point(x/rate,y/rate);}
    	ll operator | (const Point &u) const {return (x*u.y-y*u.x);}
    	ll operator & (const Point &u) const {return (x*u.x+y*u.y);}
    }a[N];
    struct Pop {
    	Point p; f2 k;
    	Pop() {}
    	Pop(Point p_,f2 k_) {p=p_,k=k_;}
    	bool operator < (const Pop &u) const {
    		return k<u.k;
    	}
    }b[N<<1];
    struct B {
    	ll a,b,c,x;
    	void prt() {
    		printf("%lld %lld %lld %lld
    ",a,b,c,x);
    	}
    	bool operator < (const B &u) const {
    		if(a==u.a) {
    			if(b==u.b) {
    				if(c==u.c) {
    					return x<u.x;
    				}else return c<u.c;
    			}else return b<u.b;
    		}else return a<u.a;
    	}
    };
    ll Abs(ll x) {return x>0?x:-x;}
    vector<B> S,T;
    B calc(Point p1,Point p2) {
    	ll dy=p2.y-p1.y,dx=p2.x-p1.x;
    	ll ta=-dy,tb=dx;
    	ll d=gcd(Abs(ta),Abs(tb));
    	if(d!=1) ta/=d,tb/=d;
    	if(ta<0) ta=-ta,tb=-tb;
    	if(ta==0) tb=Abs(tb);
    	ll tc=ta*p1.x+tb*p1.y;
    	return (B){ta,tb,tc,0};
    }
    int main() {
    	scanf("%d",&n);
    	int i,j;
    	for(i=1;i<=n;i++){
    		scanf("%lld%lld",&a[i].x,&a[i].y); a[i].x<<=1, a[i].y<<=1;
    	}
    	for(i=1;i<=n;i++) {
    		for(j=1;j<=n;j++) if(i!=j) {
    			Point mid=(a[i]+a[j])/2;
    			B tmp=calc(a[i].turn90(mid),a[j].turn90(mid));
    			tmp.x=(a[i].x+a[j].x)/2;
    			S.push_back(tmp);
    			tmp.x=(a[i].y+a[j].y)/2;
    			T.push_back(tmp);
    			//printf("%d %d %lld %lld %lld
    ",i,j,tmp.a,tmp.b,tmp.c);
    		}
    	}
    	sort(S.begin(),S.end());
    	sort(T.begin(),T.end());
    	for(i=1;i<=n;i++) {
    		Point o=a[i];
    		lb=0;
    		for(j=1;j<=n;j++) if(i!=j) b[++lb]=Pop(a[j],atan2(a[j].y-a[i].y,a[j].x-a[i].x));
    		sort(b+1,b+lb+1);
    		for(j=1;j<=lb;j++) b[j+lb]=b[j],b[j+lb].k+=2*pi;
    		int ln=lb<<1;
    		int l=0,r=0;
    		for(j=1;j<=lb;j++) {
    			rlen[j]=pf(o.x-b[j].p.x)+pf(o.y-b[j].p.y);
    			V[j]=rlen[j];
    		}
    		sort(V+1,V+lb+1);
    		int lv=unique(V+1,V+lb+1)-V-1;
    		for(j=1;j<=lb;j++) len[j]=lower_bound(V+1,V+lv+1,rlen[j])-V;
    		for(j=1;j<=lb;j++) len[j+lb]=len[j];
    		for(j=1;j<=lv;j++) c[j]=0;
    		ll ans1=0,ans2=0;
    		for(j=1;j<=lb;j++) {
    			for(;r<=ln&&b[r+1].k+eps<b[j].k+1.5*pi;) r++,ans1+=c[len[r]],c[len[r]]++;
    			for(;l<=ln&&b[l+1].k<b[j].k+0.5*pi+eps;) l++,c[len[l]]--,ans1-=c[len[l]];
    			B t=calc(o,b[j].p),tl=t,tr=t;
    			if(o.x==b[j].p.x) {
    				tl.x=o.y, tr.x=b[j].p.y;
    				if(tl.x>tr.x) swap(tl.x,tr.x);
    				ans2=lower_bound(T.begin(),T.end(),tr)-upper_bound(T.begin(),T.end(),tl);
    			}else {
    				tl.x=o.x, tr.x=b[j].p.x;
    				if(tl.x>tr.x) swap(tl.x,tr.x);
    				ans2=lower_bound(S.begin(),S.end(),tr)-upper_bound(S.begin(),S.end(),tl);
    			}
    			ans2=max(ans2,0ll);
    			//printf("%lld %lld
    ",ans1,ans2);
    			ans+=ans1*ans2;
    		}
    	}
    	printf("%lld
    ",ans<<1);
    }
    
  • 相关阅读:
    oracle 处理找被删掉且提交了事务的数据
    java去除下划线并首字母大写
    假数据仓库-常见数据枚举(日期、月份、周几、星期几,前导零、Excel 列号)
    自然语言处理标注工具——Brat(安装、测试、使用)
    判断当前点击位置在不在某个区域内
    java调用C#程序集
    UE使用EditorUtilityWidget完成简单的编辑器内工具
    CodeForces 230B
    mac中安装启动使用jmeter步骤
    Ubuntu中samba配置过程
  • 原文地址:https://www.cnblogs.com/suika/p/10676145.html
Copyright © 2011-2022 走看看