列表

详情


NC53264. 两个人的星座

描述

题目译自 JOISC 2014 Day4 T1「2 人の星座
JOI酱和IOI酱是一对亲密无间的好朋友。某天,JOI酱与IOI酱决定去山上的某个观象台进行天体观测。
从观象台上可以观测到N颗星星,编号为。每颗星星的颜色为红色、蓝色、黄色中的一种。
在观象台上观测到的星星可以用坐标系上的点来表示。在坐标系上,i号星对应的点为P_i,位于(X_i,Y_i)。坐标系上的点两两不同,且不存在三点共线。
JOI酱和IOI酱想要设立一个叫做「JOIOI座」的星座。首先。两个人决定使用红色、蓝色、黄色三种颜色的星各一个构成的三角形。他们将这样的三角形称作「好三角形」。两人将满足以下条件的一对(两个,无序)好三角形作为「JOIOI座的候补」:
  • 两个三角形没有公共点(包括内部和边界)。换言之,两个三角形之间既不相交,也不存在某个三角形包含另一个三角形。
JOI酱和IOI酱想知道构成JOIOI座的候补一共有多少种方案。
注意,如果构成三角形的6个点一样,但是构成三角形的方式不同,算作不同的方案。
现在给出观象台上能观测到的星星的信息,请求出构成「JOIOI座的候补」一共有多少种方案。

输入描述

第一行一个整数N,代表展望台上能观测到的星星的数量。
接下来N行,第i行有三个空格分隔的整数X_i,Y_i,C_i,表示i号星的坐标为(X_i,Y_i)C_i表示i号星的颜色,其中0代表红色,1代表蓝色,2代表黄色。

输出描述

输出一行一个整数,表示JOIOI座候补的方案数。

示例1

输入:

7
0 0 0
2 0 1
1 2 2
-2 1 0
-2 -3 0
0 -2 1
2 -2 2

输出:

4

说明:

星星的位置如下图。红星->圆,蓝星->菱形,黄星->三角形。
有四种JOIOI座的候补:
Snipaste_2018-10-17_22-35-19.png

示例2

输入:

8
16 0 0
17 0 0
0 7 2
0 -7 2
-1 -1 1
-1 1 2
-6 4 1
-6 -4 1

输出:

12

示例3

输入:

21
1 20 0
4 20 0
0 22 0
5 22 0
6 25 0
8 25 0
4 26 0
11 11 1
7 12 1
14 13 1
8 15 1
15 16 1
11 17 1
18 0 2
13 2 2
16 2 2
19 4 2
18 6 2
21 8 2
24 8 2
19 10 2

输出:

7748

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 1181ms, 内存消耗: 884K, 提交时间: 2022-10-19 20:27:37

#include<bits/stdc++.h>
using namespace std;

using ll = long long;

constexpr ll eps = 0;

struct point{
	ll x,y;
	friend bool operator !=(const point &lhs, const point &rhs){
		return abs(lhs.x-rhs.x)+abs(lhs.y-rhs.y) > eps;
	}
	friend point operator +(const point &lhs, const point &rhs) {
		return {lhs.x+rhs.x, lhs.y+rhs.y};
	}
	friend point operator -(const point &lhs, const point &rhs) {
		return {lhs.x-rhs.x, lhs.y-rhs.y};
	}
	friend point operator *(const ll &k, const point &t){
		return {k*t.x, k*t.y};
	}
    friend ll operator *(const point &lhs, const point & rhs) {
    	return lhs.x*rhs.y - lhs.y*rhs.x;
    }
};

using ppi = pair<point, int>;

bool argcmp (const point &a, const point &b) {
	const auto quad = [](const point &a) {
		if(a.y < -eps)  return 3;
		if(a.y >  eps)  return 1;
		if(a.x < -eps)  return 2;
		if(a.x >  eps)  return 0;
		return 0;
	};
	const int qa = quad(a), qb = quad(b);
	if(qa != qb) return qa < qb;
	return a*b > eps;
};

void solve(){
    int n; cin >> n;
    vector<ppi>vec(n);
    int n0 = 0, n1 = 0, n2 = 0;
    for(int i = 0 ; i < n ; i ++){
    	auto &[p,c] = vec[i];
    	cin >> p.x >> p.y >> c;
    	if(c==0) n0++;
    	else if(c==1) n1++;
    	else if(c==2) n2++;
    }

    ll ans = 0;
    auto solve = [&](const point &p, const int &c0)->void{

    	vector<ppi>tmp;
    	for(auto &[q,c]: vec){
    		if(q != p) tmp.push_back({q-p, c});
    	}
    	sort(tmp.begin(), tmp.end(), [](ppi &A, ppi &B){
    		return argcmp(A.first, B.first);
    	});
    	auto copy = tmp;
    	tmp.insert(tmp.end(), copy.begin(), copy.end());

        int t0 = 0, t1 = 0, t2 = 0;
        int m = tmp.size()/2;
        for(int i = 0, j = 0; i < m && (tmp[i].first.y > eps || i==0) ; i ++){
        	auto &[p1,c1] = tmp[i];
        	
        	if(c1==0) t0--;
        	else if(c1==1) t1--;
        	else t2--;

        	while(j<i+m && p1 * tmp[j].first >= 0){
        		if(tmp[j].second==0) t0++;
        		else if(tmp[j].second==1) t1++;
        		else t2++;
        		j++;
        	}

        	ll v1, v2, oc0=n0-t0, oc1=n1-t1, oc2=n2-t2;
        	if(c0==0) v1 = t1*t2, oc0--;
        	else if(c0==1) v1 = t0*t2, oc1--;
        	else v1 = t0*t1, oc2--;

        	if(c1==0) v2 = oc1 * oc2;
        	else if(c1==1) v2 = oc0 * oc2;
        	else v2 = oc0 * oc1;

        	ans += v1 * v2;
        }
    };
    for(auto &[p,c]: vec){
    	solve(p,c);
    }
    cout << ans << '\n';
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

    solve();

	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 1277ms, 内存消耗: 600K, 提交时间: 2020-08-03 20:51:32

#include<bits/stdc++.h>
#define ts cout<<"ok"<<endl
#define ll long long
#define hh puts("")
using namespace std;
int n,cnt[2][3],to[3005];
ll ans;
double PI=3.14159265358979323846;
struct point{
	double x,y,k;
	int col;
}a[3005],t[3005];
inline int read(){
    int ret=0,ff=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)){ret=(ret<<3)+(ret<<1)+(ch^48);ch=getchar();}
    return ret*ff;
}
point operator - (point A,point B){
    return (point){A.x-B.x,A.y-B.y};
}
inline bool cmp(point A,point B){
	return A.k<B.k;
}
inline ll calc(int x,int col){
	if(col==0) return 1ll*cnt[x][1]*cnt[x][2];
	else if(col==1) return 1ll*cnt[x][0]*cnt[x][2];
	else if(col==2) return 1ll*cnt[x][0]*cnt[x][1];
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i].x=read();
		a[i].y=read();
		a[i].col=read();
	}
	for(int i=1;i<=n;i++){
		int tot=0;
		for(int j=1;j<=n;j++){
			if(j==i) continue;
			t[++tot]=a[j];
			t[tot].k=atan2((a[j]-a[i]).y,(a[j]-a[i]).x);
			if(t[tot].k<=0) t[tot].k+=PI;
		}
		memset(cnt,0,sizeof(cnt));
		sort(t+1,t+tot+1,cmp);
		for(int j=1;j<=tot;j++){
			if(t[j].y<a[i].y||(t[j].y==a[i].y&&t[j].x>a[i].x)) to[j]=0,cnt[0][t[j].col]++;
			else to[j]=1,cnt[1][t[j].col]++;
		}
		for(int j=1;j<=tot;j++){
			cnt[to[j]][t[j].col]--;
			ans+=calc(0,t[j].col)*calc(1,a[i].col)+calc(0,a[i].col)*calc(1,t[j].col);
			to[j]^=1;
			cnt[to[j]][t[j].col]++;
		}
	}
	printf("%lld\n",ans>>2);
    return 0;
}

上一题