hdu 5448 Marisa’s Cake(几何+凸包)

179 篇文章 0 订阅
14 篇文章 0 订阅

题目链接:hdu 5448 Marisa’s Cake

解题思路

这题和zoj 3871 Convex Hull有点像,不过点数比较大,不能接受 o(n2) 的算法。但是题目给定的是一个凸包,所以可以通过化简,在 o(n) 的复杂度内计算出答案。

首先,对于一个三角形ABC

SABC=fA×fB+fB×fC+fC×fA(fii

那么对于i和j两点,只需要计算 fi×fj fj×fi 对ans的贡献值是多少即可。

ans=i=1nj=1i1((2ij11)×fi×fj+(2ni+j11)×fj×fi)

ans=i=1nj=1i1(2ij1×fi×fjfi×fj+2ni+j1×fj×fifj×fi)

ans=i=1nj=1i1(2ij1×fi×fj+2ni+j1×fj×fi)

ans=i=1n(2i1fi×j=1i1(2jfj)+j=1i1(2jfj)×2ni1fi)

在过程中维护 i1j=1(2jfj) i1j=1(2jfj)

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long ll;
const int maxn = 100005;
const int mod = 1e9 + 7;

struct Point {
    int x, y;
    Point(int x = 0, int y = 0): x(x), y(y) {}
    void read () { scanf("%d%d", &x, &y); }
    int operator * (const Point& u) { return (1LL * x * u.y % mod - 1LL * y * u.x % mod + mod) % mod; }
    Point operator * (const int u) { return Point(1LL * u * x % mod, 1LL * u * y % mod); }
    Point operator + (const Point& u) { return Point((x+u.x)%mod, (y+u.y)%mod); }
};

int N, mul[maxn], inv[maxn];

int mul_mod(ll x, int n, int mod) {
    int ret = 1;
    while (n) {
        if (n&1) ret = x * ret % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return ret;
}

int main () {
    mul[0] = inv[0] = 1;
    for (int i = 1; i < maxn; i++) mul[i] = 2 * mul[i-1] % mod;
    ll inv2 = mul_mod(2, mod-2, mod);
    for (int i = 1; i < maxn; i++) inv[i] = inv2 * inv[i-1] % mod;

    int cas;
    scanf("%d", &cas);
    while (cas--) {
        int ans = 0;
        scanf("%d", &N);
        Point fi, fg, fh;
        for (int i = 1; i <= N; i++) {
            fi.read();
            ans = (ans + 1LL * mul[i-1] * (fi * fh) % mod) % mod;
            ans = (ans + 1LL * (i==N?inv2:mul[N-i-1]) * (fg * fi) % mod) % mod;
            fg = fg + fi * mul[i];
            fh = fh + fi * inv[i];
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值