[hdu5448 Marisa’s Cake]多边形面积,公式化简

题意:给一个凸多边形,求任选若干点形成的多边形的面积和。

思路:

  • 按一定方向(顺时针或逆时针)对多边形的顶点进行编号,则多边形的面积计算公式为:f1 x f2 + fx f3 + ... fn-1 x f+ fn x f1,f表示从参考点到i的向量。
  • 考虑fx fj 在答案中出现的次数,则答案可以写成:fi x fj * 2n-(j-i+1) (i<j) 或 fx f* 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;
    }
}
原文地址:https://www.cnblogs.com/jklongint/p/4809042.html