题意:给一个凸多边形,求任选若干点形成的多边形的面积和。
思路:
- 按一定方向(顺时针或逆时针)对多边形的顶点进行编号,则多边形的面积计算公式为:f1 x f2 + f2 x f3 + ... fn-1 x fn + fn x f1,fi 表示从参考点到i的向量。
- 考虑fi x fj 在答案中出现的次数,则答案可以写成:fi x fj * 2n-(j-i+1) (i<j) 或 fi x fj * 2i-j-1(i>j),直接枚举i和j是O(n2)的,显然不行。
- 由叉积的性质:∑(fi x P) = (∑fi) x P,可以预处理出fi*2i-1的前缀和以及fi/2i+1的前缀和,复杂度O(n),从而只需枚举一维,另一维的和O(1)得到,总复杂度O(n)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
#pragma comment(linker, "/STACK:10240000") #include <bits/stdc++.h> using namespace std; #define X first #define Y second #define pb push_back #define mp make_pair #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) typedef long long ll; typedef pair<int, int> pii; namespace Debug { void print(){cout<<endl;}template<typename T> void print(const T t){cout<<t<<endl;}template<typename F,typename...R> void print(const F f,const R...r){cout<<f<<" ";print(r...);}template<typename T> void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;} } template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);} template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);} /* -------------------------------------------------------------------------------- */ const int maxn = 1e5 + 7; const int mod = 1e9 + 7; struct Point { ll x, y; void read() { int x, y; scanf("%d%d", &x, &y); this->x = x; this->y = y; } Point(int x, int y) { this->x = x; this->y = y; } Point() {} Point operator + (const Point &that) const { return Point((x + that.x) % mod, (y + that.y) % mod); } Point operator * (const int &m) const { return Point(x * m % mod, y * m % mod); } }; Point p[maxn], g[maxn], h[maxn]; int two[maxn], twoinv[maxn]; int cross(Point &a, Point &b) { return (a.x * b.y % mod - a.y * b.x % mod + mod) % mod; } int powermod(int a, int n, int mod) { ll ans = 1, buf = a; while (n) { if (n & 1) ans = (ans * buf) % mod; buf = buf * buf % mod; n >>= 1; } return ans; } void init() { ll inv = powermod(2, mod - 2, mod); two[0] = twoinv[0] = 1; for (int i = 1; i < maxn; i ++) { two[i] = (two[i - 1] + two[i - 1]) % mod; twoinv[i] = twoinv[i - 1] * inv % mod; } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int T, n; cin >> T; init(); while (T --) { cin >> n; for (int i = 1; i <= n; i ++) { p[i].read(); g[i] = g[i - 1] + p[i] * two[i - 1]; h[i] = h[i - 1] + p[i] * twoinv[i + 1]; } int ans = 0; for (int i = 2; i <= n; i ++) { Point buf = p[i] * two[n - i]; ans = (ans + cross(g[i - 1], buf)) % mod; } for (int i = 2; i <= n; i ++) { Point buf = p[i] * two[i]; ans = (ans + cross(buf, h[i - 1])) % mod; } cout << ans << endl; } } |
时间: 2024-10-22 01:34:45