[关闭]
@3013216027 2019-09-20T14:53:47.000000Z 字数 1503 阅读 390

在此处输入标题

未分类


小明:
小红:

假设,

综上,若,则需要满足

类似地,可以得出三种情形的结果。综合起来就是:

只需要落在以下区间内即可:

因此,可以遍历,然后求出和上述区间的4个交点(假设从下往上依次为),然后计算原数组中有多少个元素满足或者,累加起来就是总个数。当然,还有2点需要注意:
- 第1/3象限的区块包含了这条直线,而题目中还隐含了的条件,所以这条直线上的点需要排除掉
- 4个区块关于对称,这会导致对任意的也必然落在区间内,所以最后求出的结果需要除以2

下面考虑对任意的,怎么求原数组中满足的个数:只需要将数组排序,求出第一个的下标和最后一个的下标,结果就是。用二分就可以了。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef long long ll;
  6. const int MAX = 200019;
  7. ll a[MAX];
  8. int n;
  9. // find num of elements in range [low, high]
  10. int find_range(ll low, ll high, ll target) {
  11. if (low > a[n-1] || high < a[0]) {
  12. return 0;
  13. }
  14. int lb = lower_bound(a, a + n, low) - a;
  15. int ub = upper_bound(a, a + n, high) - a - 1;
  16. // printf("find_range(%d,%d)=%d\n", low, high, ub - lb);
  17. if (a[lb] <= target && target <= a[ub]) {
  18. return ub - lb < 0 ? 0 : ub - lb;
  19. }
  20. return ub - lb + 1;
  21. }
  22. int main() {
  23. while (~scanf("%d", &n)) {
  24. for (int i = 0; i < n; i++) {
  25. scanf("%lld", a + i);
  26. }
  27. sort(a, a + n);
  28. ll sum = 0LL;
  29. for (int i = 0; i < n; i++) {
  30. if (a[i] < 0) {
  31. sum += find_range(a[i]<<1, a[i]-1>>1, a[i]);
  32. sum += find_range(-a[i]-1>>1, -a[i]<<1, a[i]);
  33. } else {
  34. sum += find_range(-a[i]<<1, -a[i]-1>>1, a[i]);
  35. sum += find_range(a[i]+1>>1, a[i]<<1, a[i]);
  36. }
  37. }
  38. printf("%lld\n", sum>>1);
  39. }
  40. return 0;
  41. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注