题意
给定2000个点,求所有锐角三角形的面积
题解
核心策略就是求出所有锐角的面积作为S1,再求出所有非锐角的面积作为S2,已知一个锐角三角形面积在S1中算了3次,非锐角三角形中的锐角在S1中算了2次,因此答案为
(
S
1
−
2
∗
S
2
)
/
3
(S1-2*S2)/3
(S1−2∗S2)/3
枚举每个点做极角排序,将环扩充成链,预处理出x,y轴的前缀和,之后双指针扫出角度相同、角度为锐角,角度小于180的指针位置,即可在O(n^2logn)的时间复杂度下求解
代码
/**
* author: TelmaZzzz
* create: 2019-10-08-19.17.16
**/
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
//#include <random>
using namespace std;
typedef long long ll;
typedef __int128 LL;
typedef unsigned long long ull;
typedef double db;
void _R(int &x) { scanf("%d", &x); }
//void _R(ll &x) { scanf("%lld", &x); }
void _R(db &x) { scanf("%lf", &x); }
void _R(char &x) { scanf(" %c", &x); }
void _R(char *x) { scanf("%s", x); }
void R() {}
template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); }
void _W(const int &x) { printf("%d", x); }
//void _W(const ll &x) { printf("%lld", x); }
void _W(const db &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
template<class T> void _W(const vector<T> &x) { for (auto i = x.begin(); i != x.end(); _W(*i++)) if (i != x.cbegin()) putchar(' '); }
void W() {}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define erp(x,y,z) for(int x=y;x>=z;x--)
#define PB push_back
#define MP make_pair
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
#define Fi first
#define Se second
//#pragma comment(linker,"/STACK:10240000,10240000")
//mt19937 rand_(time(0));
const int N=4200,M=2e6;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){ll ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[M],ver[M],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
template <class T>
void read(T &x) {
static char ch;static bool neg;
for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
x=neg?-x:x;
}
void TelmaZzzz(){
#ifndef ONLINE_JUDGE
freopen("1.txt","r",stdin);
#endif
}
#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
#define ocross(p1,p2,p3) sign(cross(p1,p2,p3))
const ll mod=998244353;
inline int sign(LL a){return a<0?-1:a>0;}
struct P{
ll x,y;
P(){}
P(ll _x,ll _y) : x(_x), y(_y){}
P operator+(P p){return {x+p.x,y+p.y};}
P operator-(P p){return {x-p.x,y-p.y};}
P operator*(ll d){return{x*d,y*d};}
P operator/(ll d){return{x/d,y/d};}
void scan(){
ll k1,k2;
read(k1);
read(k2);
x=k1,y=k2;
}
int quad()const{return sign(y)==1||(sign(y)==0&&sign(x)>=0);}
LL det(P p){return (LL)x*p.y-(LL)y*p.x;}
}p[N],que[N];
ll sumx[N],sumy[N];
int getxx(P a) {
if(a.x>0 && a.y>=0) return 1;
if(a.x<=0 && a.y>0) return 2;
if(a.x<0 && a.y<=0) return 3;
if(a.x>=0 && a.y<0) return 4;
}
bool cmp(P a,P b){
if(a.quad()!=b.quad()){
return a.quad()<b.quad();
}
else {
return sign(a.det(b))>0;
}
}//¼«½ÇÐò
LL dep(P a,P b){
return (LL)a.x*b.x+(LL)a.y*b.y;
}
LL det(P a,P b){
return (LL)a.x*b.y-(LL)a.y*b.x;
}
int sdep(P a,P b){
return sign(dep(a,b));
}
int sdet(P a,P b){
return sign(det(a,b));
}
int main(){
TelmaZzzz();
//ios::sync_with_stdio(false);
int t;
R(t);
int n;
while(t--){
R(n);
rep(i,1,n){
p[i].scan();
}
ll sum=0;
ll del=0;
rep(i,1,n){
int tot=0;
rep(j,1,n){
if(i==j) continue;
que[++tot]=p[j]-p[i];
}
int m=tot;
sort(que+1,que+1+m,cmp);
rep(j,1,m) que[j+m]=que[j];
rep(j,1,2*m){
sumx[j]=(sumx[j-1]+que[j].x)%mod;
sumy[j]=(sumy[j-1]+que[j].y)%mod;
}
int e0=1,e1=1,tt=1;
ll tmps=0;
ll tmpd=0;
rep(j,1,m){
tt=max(tt,j);
P ee0=P(-que[j].y,que[j].x);
P ee1=P(-que[j].x,-que[j].y);
while(tt<2*m&&sdet(que[tt],que[j])==0) tt++;
e0=max(e0,tt);
while(e0<2*m&&sdet(que[e0],ee0)>0&&sdet(que[e0],que[j])<0) e0++;
e1=max(e1,e0);
//cout<<sdet(que[e1],ee1)<<' '<<sdet(que[e1],ee0)<<endl;
while(e1<2*m&&sdet(que[e1],ee1)>0&&sdet(que[e1],ee0)<=0) e1++;
sum+=(-((sumx[e0-1]-sumx[tt-1]+mod+mod)%mod*(que[j].y%mod)%mod)+(sumy[e0-1]-sumy[tt-1]+mod+mod)%mod*(que[j].x%mod)%mod+mod)%mod;
sum%=mod;
del+=(-((sumx[e1-1]-sumx[e0-1]+mod+mod)%mod*(que[j].y%mod)%mod)+(sumy[e1-1]-sumy[e0-1]+mod+mod)%mod*(que[j].x%mod)%mod+mod)%mod;
del%=mod;
}
}
sum=(sum-del+mod-del+mod)%mod*inv2(3LL,mod)%mod;
printf("%lld\n",(long long)sum);
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}