P5545 [JSOI2016] 炸弹攻击2
题意
给出 \(3\) 类点 \(S,T,D\),分别有 \(S,T,D\) 个。求满足条件的四元组 \((i,j,k,l)\) 的数量,满足线段 \(S_iD_l\) 和线段 \(T_jT_k\) 相交。
\(S,T,D\le800\),类型 \(S\) 和 \(T\) 的点 \(y\) 坐标均小于 \(0\)。
思路
枚举一个 \(S\) 类点,以祂为原点建系,把所有 \(T\) 和 \(D\) 类点按照与 \(x\) 正半轴的夹角排序,那么两个 \(T\) 类点和任意一个夹在祂们之间的 \(D\) 类点会构成一个合法组合。暴力枚举这两个 \(T\) 类点,用前缀和计算数量。
注意以下几点:
- 夹在两个 \(T\) 类点之间的点是祂们两个所成的劣交所对的点,而不是与 \(x\) 正半轴的夹角大小在两个 \(T\) 类点之间的点。
- 反三角函数常数大,可以提前计算好,不然会 \(TLE\)。
代码
// Problem: P5545 [JSOI2016] 炸弹攻击2
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5545
// Memory Limit: 500 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define LL long long
const int maxn=810;
const double PI=3.14159265358979323846;
int D,S,T,ans,sum[maxn*2];
struct point{int x,y;}d[maxn],s[maxn],t[maxn];
double getang(point d){return atan2(d.y,d.x);}
struct node{
point d;
int type;
double ange;
bool operator<(const node t)const{return ange<t.ange;}
void init(){ange=getang(d);}
};
vector<node>vt;
inline void read(point&x){read(x.x,x.y);}
point getvec(point a,point b){return{b.x-a.x,b.y-a.y};}
LL operator*(const point a,const point b){return 1ll*a.x*b.y-1ll*b.x*a.y;}
int calcsum(int l,int r){
if(l>r) return 0;
if(l==0) return sum[r];
return sum[r]-sum[l-1];
}
signed main(){
read(D);
for(int i=1;i<=D;i++) read(d[i]);
read(S);
for(int i=1;i<=S;i++) read(s[i]);
read(T);
for(int i=1;i<=T;i++) read(t[i]);
LL ans=0;
for(int i=1;i<=S;i++){
vt.clear();
for(int j=1;j<=T;j++) vt.push_back({getvec(s[i],t[j]),1}),vt.back().init();
for(int j=1;j<=D;j++) vt.push_back({getvec(s[i],d[j]),2}),vt.back().init();
sort(vt.begin(),vt.end());
sum[0]=(vt[0].type==2);
for(int i=1;i<vt.size();i++) sum[i]=sum[i-1]+(vt[i].type==2);
for(int i=0;i<vt.size();i++) for(int j=i+1;j<vt.size();j++){
if(vt[i].type!=1) break;
if(vt[j].type!=1) continue;
if(vt[j].ange-vt[i].ange>PI) ans+=calcsum(0,i)+calcsum(j,vt.size()-1);
else ans+=calcsum(i,j);
}
}
write(ans);
return 0;
}

浙公网安备 33010602011771号