【hdu5448】Marisa’s Cake

题意:给你一个包含n个点的凸包,所有可能出现的子凸包的面积和。

分析:首先比较暴力的方法就是n^2枚举一条边,求它对答案的贡献。但是点的个数有10^5,因此我们考虑从某一个点出发的所有有向面积。

若我们当前考虑的是第i个点,那么它与第i+1个点形成的这条边所能产生的凸包个数为(2^(n - 2) - 1)个,与第i + 2个点形成的这条边的个数为(2 ^ (n - 3) - 1)个……又因为叉积满足分配律,因此可以先搞出来一个前缀和。而当在考虑第i + 1个点时,只需要把第i + 1个点的贡献减掉,然后再把除了第i个点的贡献乘2+1即可。复杂度为o(n)

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
using namespace std;
typedef long long LL;
const int mod = 1000000007, N = 100005;
int T, n, ans;
LL a[N], b[N], sa[N], sb[N], s2[N];
LL Cross(int i, int j) { return (a[i] * b[j] % mod - b[i] * a[j] % mod + mod) % mod; }
int main()
{
    scanf("%d", &T);
    while (T --) {
        scanf ("%d", &n);
        s2[0] = 1;
        Rep(i, 1, n) s2[i] = s2[i - 1] * 2 % mod;
        ans = 0, a[n + 1] = b[n + 1] = 0;
        Rep(i, 1, n) scanf ("%I64d%I64d", &a[i], &b[i]);
        Rep(i, 1, n) {
            sa[i] = (sa[i - 1] + a[i]) % mod;
            sb[i] = (sb[i - 1] + b[i]) % mod;
        }
        Rep(i, 2, n - 1) {
            (a[n + 1] += a[i] * (s2[n - i] - 1)) %= mod;
            (b[n + 1] += b[i] * (s2[n - i] - 1)) %= mod;
        }
        Rep(i, 1, n) {
            ans = (ans + Cross(i, n + 1)) % mod;
            int x = i - 1, y = i % n + 1; if (!x) x = n;
            (a[n + 1] -= a[y] * (s2[n - 2] - 1) % mod - mod) %= mod;
            (b[n + 1] -= b[y] * (s2[n - 2] - 1) % mod - mod) %= mod;
            a[n + 1] = ((a[n + 1]) * 2 + (sa[n] - a[y] - a[i]) % mod + mod) % mod;
            b[n + 1] = ((b[n + 1]) * 2 + (sb[n] - b[y] - b[i]) % mod + mod) % mod;
        }
        printf("%d\n", ans);
    }

    return 0;
}
View Code

 

posted @ 2015-09-16 16:47  Owen_hzt  阅读(186)  评论(0编辑  收藏  举报