Regionals 2012, Asia - Hatyai 组队赛130912

B题:在圆上找三个点构成锐角三角形,求锐角三角形的个数。

一般构造三角形的问题,直接求锐角不好求,要判断三个角都不是钝角才行。所以从反面求,把总的三角形减去直角和钝角就行了,而直角和钝角只要判断一次。

由于n比较大,O(n^2)的算法不行,只能是O(n)的算法。

每次求出从第i个点开始,沿逆时针方向找两个点构成钝角或直角三角形。而且j的从0开始,枚举与i的点形成的角度在180度之内的所有的点。这样求出来的三角形不会重复。具体可以画图验证下。

注意有一个问题:判断直角的时候,统一把a[i]+180+eps,判断a[j]<=a[i]+180+eps,这样每次找到的点都是形成的角度超过180的点,就从(j-i+1)-2中取2个点。

因为环的原因,化成线性的时候要增加n个点。

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 10005
#define INF 0xfffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define FOR(i,s,t) for(int i=s;i<=t;i++)
#define ull unsigned long long
#define ll long long
#define eps 1e-8
using namespace std;
double a[2*20005];
int main()
{
    int n,r;
    int tt=1;
    while(scanf("%d%d",&n,&r)!=EOF)
    {
        if(!n&&!r) break;
        for(int i=0;i<n;i++)
        {
            scanf("%lf",&a[i]);
        }
        sort(a,a+n);
        for(int i=0;i<n;i++)
        {
            a[n+i]=a[i]+360;
        }
        printf("Case %d: ",tt++);
        ll ans=(ll)n*(n-1)*(n-2)/6;
        ll tmp=0;
        int j=0;
        for(int i=0;i<n;i++)
        {
            int cnt=0;
            while(a[j]<=a[i]+180+eps)//这里使每个点都是形成的角度差大于180的点
            {
                j++;
                cnt++;
            }
            ll k=(ll)(j-i-1);
            tmp+=k*(k-1)/2;
        }
        printf("%lld\n",ans-tmp);
    }
	return 0;
}
D题:求两个圆覆盖的所有点数。

因为有200000个点,只能用O(nlogn)的算法,所以一旦把每个点按到圆心的距离排序后,就能按用解决线性的二分法找到满足条件的点数。

H,I,J就不多说了,思路比较简单。

不过J题个人感觉还是用string比较方便,不过得注意下第一个字符和最后几个字符可能含有多个其他字符。

你可能感兴趣的:(Regionals 2012, Asia - Hatyai 组队赛130912)