zoj 3871
貌似这道题某人已经扔给我一个多星期了(雾)
首先要知道这样一点:凸包的面积可以直接用线段的有向面积和求得。
自己口胡的证明:单纯一条线段自身的叉积就是到原点与这条线段构成三角形的面积吧,那么加加减减之后就是凸包的面积了。。
所以我们可以单独考虑每条边的贡献。
显然一条边的贡献,就是在它 一侧 点的集合的 非空子集 的 数目。
所以我们枚举点然后极角排序扫一遍。
貌似除了自己手残写错了没有什么大坑?(雾)
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long double db; 4 typedef long long ll; 5 const ll mod = 998244353; 6 const db eps=1e-6; 7 const db pi=acos(-1); 8 int sign(db k){if(k>-eps)return 1;else if(k<-eps)return -1; return 0;} 9 int cmp(db k1,db k2){ return sign(k1-k2);} 10 struct point{ 11 ll x,y; 12 db ang; 13 point operator+(const point &k1)const { return point{x+k1.x,y+k1.y};} 14 point operator-(const point &k1)const { return point{x-k1.x,y-k1.y};} 15 db getw(){ return atan2(1.0*y,1.0*x);} 16 }; 17 ll cross(point k1,point k2){ return (k1.x*k2.y%mod-k1.y*k2.x%mod+2*mod)%mod;} 18 bool cmp2(point a,point b){ 19 return a.ang<b.ang; 20 } 21 ll f[1551]; 22 void init(){ 23 f[0]=1; 24 for(int i=1;i<=1234;i++){ 25 f[i]=f[i-1]*2%mod; 26 } 27 } 28 point p[2333]; 29 int t,n; 30 point v[2333]; 31 int cnt=0; 32 ll slove(int id){ 33 cnt=0; 34 for(int i=1;i<=n;i++){ 35 if(i==id)continue; 36 v[cnt++]=point{p[i].x,p[i].y,(p[id]-p[i]).getw()}; 37 } 38 for(int i=0;i<cnt;i++){ 39 v[i+cnt]=point{v[i].x,v[i].y,v[i].ang+2*pi}; 40 } 41 sort(v,v+2*cnt,cmp2); 42 ll res=0; 43 for(int l=0,r=0;l<cnt;l++){ 44 while (r<2*cnt&&v[r].ang-v[l].ang<pi){ 45 r++; 46 } 47 res+=cross(p[id],v[l])*((f[r-l-1]-1+mod)%mod)%mod; 48 res%=mod; 49 } 50 return res; 51 } 52 int main(){ 53 //freopen("zoj3871.in","r",stdin); 54 init(); 55 scanf("%d",&t); 56 while (t--){ 57 scanf("%d",&n); 58 ll ans = 0; 59 for(int i=1;i<=n;i++){ 60 scanf("%lld%lld",&p[i].x,&p[i].y); 61 } 62 for(int i=1;i<=n;i++) { 63 ans += slove(i); 64 ans%=mod; 65 } 66 printf("%lld\n",ans); 67 } 68 }