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