Regionals 2012, Asia - Hatyai 组队赛130912

来源:互联网 发布:php求数组最大值 编辑:程序博客网 时间:2024/04/30 00:38

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-8using 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比较方便,不过得注意下第一个字符和最后几个字符可能含有多个其他字符。