题目:http://acm.hdu.edu.cn/showproblem.php?pid=5448
题意:
给定一个由
n
个整点构成的凸多边形,求从
n≤100000
,坐标
∈[0,109]
。
题解:
面积乘
2
的话直接算叉积就好了,例如三个点
直接算每种情况的多边形求面积是
O(n2n)
的,但是我们可以发现计算面积的过程中有很多的重复计算。
对于两个在原多边形上的点
i,j
,我们可以算出它们产生的贡献
fi×fj
在多少个需要算的多边形
M={a0,a1,...,ap−1}
的式子里出现。
首先如果
at=i
,那么必须有
a(t+1)modp=j
,也就是说按逆时针顺序在
i
和
于是答案可以被表示为
如果令
答案就是
于是在模意义下预处理 2i 和 2−i ,边利用前缀和的特点维护 g(i),h(i) ,边统计答案就行了,时间复杂度 O(n) 。
代码:
#include <cstdio>
typedef long long LL;
const int maxn = 100010, mod = 1000000007, inv2 = 500000004;
int t, n, pw1[maxn], pw2[maxn], x, y, pre1x, pre1y, pre2x, pre2y, ans;
int mod_add(int x, int y)
{
x += y;
if(x >= mod)
x -= mod;
return x;
}
int mod_sub(int x, int y)
{
x -= y;
if(x < 0)
x += mod;
return x;
}
int det(int x1, int y1, int x2, int y2)
{
return mod_sub((LL)x1 * y2 % mod, (LL)x2 * y1 % mod);
}
int main()
{
scanf("%d", &t);
pw1[0] = 1;
for(int i = 1; i < maxn; ++i)
pw1[i] = (LL)pw1[i - 1] * 2 % mod; // +
pw2[0] = 1;
for(int i = 1; i < maxn; ++i)
pw2[i] = (LL)pw2[i - 1] * inv2 % mod; // -
while(t--)
{
scanf("%d", &n);
pre1x = pre1y = pre2x = pre2y = ans = 0;
for(int i = 1; i <= n; ++i)
{
scanf("%d%d", &x, &y);
ans = mod_add(ans, (LL)pw1[i - 1] * det(x, y, pre2x, pre2y) % mod);
ans = mod_add(ans, (LL)(i == n ? inv2 : pw1[n - i - 1]) * det(pre1x, pre1y, x, y) % mod);
pre1x = mod_add(pre1x, (LL)x * pw1[i] % mod); // +
pre1y = mod_add(pre1y, (LL)y * pw1[i] % mod); // +
pre2x = mod_add(pre2x, (LL)x * pw2[i] % mod); // -
pre2y = mod_add(pre2y, (LL)y * pw2[i] % mod); // -
}
printf("%d\n", ans);
}
return 0;
}
逗比小记:
场上拿
∑ni=1∑nj=i+1∑nk=j+12n−1−i+j−k(fi×fj+fj×fk+fk×fi)
算的,自己折磨自己不说,还拖我队后腿啊。