官网的图感觉很好,我就盗过来了。。。。(无视掉最后一张图
首先求出来每个点它向前向后最远能连到哪里l[i],r[i]
然后枚举a这个点,那么他向前最多能到达C这个点,那么对于他向后到达的b这个点,有很多情况,比如上图是三种情况
对于每种情况,我们可以看得出所形成三角形个数是r[b]-b-(C-1-b),当然r[b]就是图中的f(b)
因为b是连续的
那么对于这个式子,我们可以对r[b]-b求个sum数组,用的时候O(1)得到,后面减去的(C-1-b)这是个等差数列,也能O(1)得到。
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <ctime> #include <cstring> using namespace std; class EnclosingTriangle { public: long long getNumber(int, vector<int> , vector<int> ); }; #define M 60000 pair<int, int> coo[20 * M]; long long l[20 * M], r[20 * M]; long long sumr[20 * M]; struct TPoint { long long x, y; TPoint() { } TPoint(const int &_x, const int &_y) : x(_x), y(_y) { } }; long long cross(const TPoint & a, const TPoint & b, const TPoint & c) { return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); } vector<int> X, Y; bool check(TPoint a, TPoint b) { for (int i = 0; i < X.size(); ++i) { if (cross(a, b, TPoint(X[i], Y[i])) < 0) return false; } return true; } long long EnclosingTriangle::getNumber(int m, vector<int> x, vector<int> y) { int n = 0; int i, j, k; int up, down, mid; X = x; Y = y; for (i = 0; i <= m; ++i) { coo[n++] = make_pair(0, i); } for (i = 1; i <= m; ++i) { coo[n++] = make_pair(i, m); } for (i = m - 1; i >= 0; --i) { coo[n++] = make_pair(m, i); } for (i = m - 1; i > 0; --i) { coo[n++] = make_pair(i, 0); } for (i = 0; i < n; ++i) { coo[i + n] = coo[i]; coo[i + 2 * n] = coo[i]; } for (i = n; i < 2 * n; ++i) { up = i - n + 1; down = i - 1; while (down - up > 0) { mid = (up + down) / 2; if (check(TPoint(coo[i].first, coo[i].second), TPoint( coo[mid].first, coo[mid].second))) down = mid; else up = mid + 1; } l[i] = l[i - n] = l[i + n] = i - down; up = i + n - 1; down = i + 1; while (up - down > 0) { mid = (up + down + 1) / 2; if (check(TPoint(coo[mid].first, coo[mid].second), TPoint( coo[i].first, coo[i].second))) down = mid; else up = mid - 1; } r[i] = r[i - n] = r[i + n] = down - i; } sumr[0] = r[0]; for (i = 1; i < 3 * n; ++i) sumr[i] = r[i] + sumr[i - 1]; long long ans = 0; for (i = n; i < 2 * n; ++i) { int c = i - l[i]; int left = c - l[c] + n; if (left == i) left++; int right = i + r[i]; if (right < left) continue; ans += sumr[right] - sumr[left - 1]; ans -= (long long)(c + n - right + c + n - left - 2) * (right - left + 1) / 2; if (right == c + n) ans--; if (r[i] + r[right] == n) ans--; } return ans / 3; }