kmjp's blog

競技プログラミング参加記です

TopCoder SRM 641 Div1 Easy TrianglesContainOrigin、Div2 Medium TrianglesContainOriginEasy

SRM641に参加。
Easyをそこそこの時間で解き、1Challengeでレート微増。
http://community.topcoder.com/stat?c=problem_statement&pm=13309
http://community.topcoder.com/stat?c=problem_statement&pm=13547

問題

2次元座標上でN個の点の位置が与えられる。
このうち3つの点の組のうち、3点を頂点とする三角形が原点を含むものの数を求めよ。

なお、3点が同一線上にあったり、2点の同一線上に原点が来ることはない。

解法

Div2 MediumはN<=50のため、3点総当たりで全パターンの三角形を試せばよい。
Div1 EasyはN<=250のためO(N^3)では間に合わない。

そこでまず全部の点を偏角の順にソートする。
そして2点i,jを総当たりし、3点目として取れる点の数を列挙すればよい。
先に決めた2点の偏角をarg(i)、arg(j)とすると、3点目kの偏角がarg(i)+π<arg(k)<arg(j)+πとなるkの数を求めればよい。

条件を満たすkの数は、偏角順にソートした点に対しlower_bound等で求めればO(N^2*logN)だし、尺取法ならO(N^2)で求めることができる。
以下の解法は前者。

class TrianglesContainOrigin {
	public:
	int N;
	long long count(vector <int> x, vector <int> y) {
		int i,j;
		ll ret=0;
		double pi=atan(1)*4;
		N=x.size();
		vector<double> V;
		FOR(i,N) {
			double d=atan2(y[i],x[i]);
			if(d<0) d+=2*pi;
			V.push_back(d);
		}
		sort(V.begin(),V.end());
		FOR(i,N) for(j=i+1;j<N;j++) {
			if(V[j]<V[i]+pi) {
				int x2=lower_bound(V.begin(),V.end(),V[i]+pi)-V.begin();
				int y2=lower_bound(V.begin(),V.end(),V[j]+pi)-V.begin();
				ret+=y2-x2;
			}
		}
		
		return ret;
	}
}
||

*まとめ