HihoCoder 1879 J - Rikka with Triangles (计算几何)

该博客详细介绍了如何利用计算几何的方法解决HihoCoder上的1879题——Rikka与锐角三角形。博主首先阐述了题意,即给出2000个点,要求找出所有锐角三角形的面积。接着,博主提出了一种策略,计算所有锐角和非锐角三角形的面积,通过面积差除以3来得到答案,因为锐角三角形被算了3次,而非锐角的锐角被算了2次。为了实现这个策略,博主进行了极角排序,并预处理了x、y轴的前缀和,最后使用双指针技术在O(n^2 log n)的时间复杂度内解决了问题。
摘要由CSDN通过智能技术生成

题意

给定2000个点,求所有锐角三角形的面积

题解

核心策略就是求出所有锐角的面积作为S1,再求出所有非锐角的面积作为S2,已知一个锐角三角形面积在S1中算了3次,非锐角三角形中的锐角在S1中算了2次,因此答案为 ( S 1 − 2 ∗ S 2 ) / 3 (S1-2*S2)/3 (S12S2)/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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值