結果
| 問題 |
No.3154 convex polygon judge
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-05-21 02:48:15 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 106 ms / 2,000 ms |
| コード長 | 18,377 bytes |
| コンパイル時間 | 8,437 ms |
| コンパイル使用メモリ | 325,708 KB |
| 実行使用メモリ | 28,908 KB |
| 最終ジャッジ日時 | 2025-05-21 02:48:26 |
| 合計ジャッジ時間 | 9,701 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 44 |
ソースコード
#include <bits/stdc++.h>
//#include <ranges>
#define _USE_MATH_DEFINES
//aclをatcoder以外で使うときは'combine [ファイル名]'とターミナルに打てばよい
// #include <atcoder/dsu>
#include <atcoder/all>
using namespace atcoder;
using mint = modint998244353;
// using mint = modint1000000007;
using namespace std;
// using mint = modint;
using ll = long long;
using ld = long double;
using lll=__int128_t;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define rep2(i, s, n) for (ll i = (s); i < (ll)(n); i++)
#define rrep(i,a,b) for(ll i=a;i>=b;i--)
#define fore(i,a) for(auto &i:a)
#define V vector<ll>
#define Vi vector<int>
#define Vd vector<double>
#define Vld vector<long double>
#define Vb vector<bool>
#define Vs vector<string>
#define Vc vector<char>
#define VV vector<V>
using P = pair<ll,ll>;
using G = vector<vector<ll>>;
#define VP vector<P>
#define VT vector<tuple<ll,ll,ll>>
template<typename T> using min_priority_queue = priority_queue<T, vector<T>, greater<T>>;
#define all(a) (a).begin(),(a).end()
#define rall(a) (a).rbegin(),(a).rend()
#define INF 1LL << 60
#define inf 1e9
template <typename T>
bool chmax(T &a, const T& b) {
if (a < b) {
a = b; // aをbで更新
return true;
}
return false;
}
template <typename T>
bool chmin(T &a, const T& b) {
if (a > b) {
a = b; // aをbで更新
return true;
}
return false;
}
long long combi(long long n, long long k) {
if (n == k || k == 0)
return 1;
else {
return combi(n - 1, k - 1) + combi(n - 1, k);
}
}
//二項係数
#define CMAX 1010
int noinit = 1; ll acbmemo[CMAX][CMAX];
ll aCb(ll a, ll b) {
if (noinit) {
rep2(i, 0, CMAX) rep2(j, 0, CMAX) acbmemo[i][j] = -1;
noinit = 0;
}
if (b == 0 || a == b) return 1;
if (0 <= acbmemo[a][b]) return acbmemo[a][b];
return acbmemo[a][b] = aCb(a - 1, b - 1) + aCb(a - 1, b);
}
//整数かどうか
bool isNumber(const string& str)
{
for (const char &c : str) {
if (std::isdigit(c) == 0) return false;
}
return true;
}
///*
//最大公約数
ll gcd(ll a, ll b){
if(b==0){
return a;
}else{
return gcd(b, a%b);
}
}
//最小公倍数
ll lcm(ll a, ll b){
ll g=gcd(a,b);
return a/g*b;
}
std::ostream &operator<<(std::ostream &dest, __int128_t value) {
std::ostream::sentry s(dest);
if (s) {
__uint128_t tmp = value < 0 ? -value : value;
char buffer[128];
char *d = std::end(buffer);
do {
--d;
*d = "0123456789"[tmp % 10];
tmp /= 10;
} while (tmp != 0);
if (value < 0) {
--d;
*d = '-';
}
int len = std::end(buffer) - d;
if (dest.rdbuf()->sputn(d, len) != len) {
dest.setstate(std::ios_base::badbit);
}
}
return dest;
}
//*/
//int di[] = {-1,0,1,0};
//int dj[] = {0,-1,0,1};
//s = regex_replace(s, regex("あ"), "う");
/*stiring で char を検索するときは
s.find(c)!=string::npos
*/
/*//各桁の和
int wa(int n){
int sum =0;
while(n>0){
sum += n%10;
n/=10;
}
return sum;
}
*/
//
/*
//階乗
int ki(int i){
int k = 1;
for(int j = 1; j<=i; j++){
k *= j;
}
return k;
}
//
*/
/*log_x(b)
double logN(double x, double b) {
return log(x) / log(b);
}
*/
///*
//エラトステネスの篩O(NloglogN) main関数内にSieveofEratosthenes();を書き込む!!
const ll N = 5050505;//求める範囲
Vb isp(N+1,true);
void SieveofEratosthenes(){
isp[0] = false;
isp[1] = false;
for(ll i = 2; i+i<=N;i++){
if(isp[i])for(ll j = 2; i*j<=N;j++)isp[i*j] = false;
}
}
//*/
///*
//約数列挙 O(√n)
vector<long long> divisor(long long n) {
vector<long long> ret;
for (long long i = 1; i * i <= n; i++) {
if (n % i == 0) {
ret.push_back(i);
if (i * i != n) ret.push_back(n / i);
}
}
sort(ret.begin(), ret.end()); // 昇順に並べる
return ret;
}
//*/
//
/*
//素因数分解O(√n)
map< ll, ll > prime_factor(ll n) {
map< ll, ll > ret;
for(ll i = 2; i * i <= n; i++) {
while(n % i == 0) {
ret[i]++;
n /= i;
}
}
if(n != 1) ret[n] = 1;
return ret;
}
//
*/
/*
ll modpow(ll x, ll n, ll mod){
while(n){
ll resu = 1;
if(n&1)res = (res * x) %mod;
x = (x*x)%mod;
n>>=1;
}
return res;
}
*/
///*
//最小二乗法
//aのb乗をmで割ったあまりを返す関数
//変数aはa^1→a^2→a^4→a^8→…と変化
ll power(ll a,ll b, ll m){
ll p = a,ans = 1;
rep(i,60){
ll wari = (1LL<<i);
if((b/wari)%2==1){
ans=(ans*p)%m;
}
p=(p*p)%m;
}
return ans;
}
//*/
//
/*
//0~xまでのxor累積和
ll xor_sum(ll x){
if(x%2!=0){
x-1;
if((x/2)%2==0)return 1;
else return 0;
}else{
if(x%4==0)return x;
else return x+1;
}
}
//
*/
/*
template <typename T> bool next_combination(const T first, const T last, int k) {
const T subset = first + k;
// empty container | k = 0 | k == n
if (first == last || first == subset || last == subset) {
return false;
}
T src = subset;
while (first != src) {
src--;
if (*src < *(last - 1)) {
T dest = subset;
while (*src >= *dest) {
dest++;
}
iter_swap(src, dest);
rotate(src + 1, dest + 1, last);
rotate(subset, subset + (last - dest) - 1, last);
return true;
}
}
// restore
rotate(first, subset, last);
return false;
}
//
*/
int ctoi(char c){
if(c>='0' and c<='9')return c-'0';
else return -inf;
}
char touplo(char c){
char ret=c;
ret^=32;
return ret;
}
//vector<int> dx = {1,0,-1,0,1,-1,-1,1};
//vector<int> dy = {0,1,0,-1,1,1,-1,-1};
//時計回り
int clx[4] = { 0, 1, 0, -1}, cly[4] = { -1, 0, 1, 0 };
//反時計回り
int cclx[4] = { 0, -1, 0, 1}, ccly[4] = { -1, 0, 1, 0 };
int dx[8] = { 0, 1, 0, -1, 1, 1, -1, -1 }, dy[8] = { 1, 0, -1, 0, 1, -1, 1, -1 };
// int dx[8]={0,-1,-1,-1,0,1,1,1},dy[8]={1,1,0,-1,-1,-1,0,1};
//#define mod 998244353
//cout << mint.val() << endl;
//cout << fixed << setprecision(15) << y << endl;
P mima(int a,int b){
P ret;
ret=make_pair(min(a,b),max(a,b));
return ret;
}
//bit s に i番目のビットを立てる
#define bittate(s,i) (s|(1LL<<i))
//bit sから i番目のビットを消す
#define bitkeshi(s,i) (s^(1LL<<i))
//bit s が i番目のビットを含んでいるか
bool bitcheck(ll s,ll i){
if((s>>i)&1LL)return true;
else return false;
}
//string str(bitset<32>(value).to_string<char, char_traits<char>, allocator<char> >());
#define ppc(n) __popcount(n)
string lltobin(ll n){
string re((bitset<61>(n).to_string<char, char_traits<char>, allocator<char> >()));
return re;
}
ll bintoll(string s){
ll re=stoll(s,nullptr,2);
return re;
}
//-1なら外れてる、それ以外なら座標を1次元に変換
ll kabe_check(ll i,ll j,ll h,ll w){
if((i<0 or h<=i or j<0 or w<=j))return -1;
else return i*w+j;
}
#define yes "Yes"
#define no "No"
#define Yes "YES"
#define No "NO"
#include<complex>
namespace geometry{
using ld=long double;
using point=complex<ld>;
const ld eps=1e-9;
const ld PI=acos(ld(-1));
inline bool equal(const ld &a,const ld &b){
return fabs(a-b)<eps;
}
//単位ベクトル
point unitVector(const point &a){
return a/abs(a);
}
//法線ベクトル
point normalVector(const point &a){
return a*point(0,1);
}
//内積: a*b=|a||b|cosθ
ld dot(const point &a, const point &b){
return (a.real()*b.real()+a.imag()*b.imag());
}
//外積: a×b=|a||b|sinθ
ld cross(const point &a, const point &b){
return (a.real()*b.imag()-a.imag()*b.real());
}
//反時計回りに回転(ラジアン)
point rotate(const point &p, const ld &theta){
return point(cos(theta)*p.real()-sin(theta)*p.imag(),
sin(theta)*p.real()+cos(theta)*p.imag());
}
//ラジアンー>度
ld radianTodegree(const ld &radian){return radian *180/PI;}
//度ー>ラジアン
ld degreeToradian(const ld °ree){return degree *PI/180;}
//点の回転方向
//点aを基準にしてb,cの位置関係
int ccw(const point &a, point b,point c){
b-=a,c-=a;
//反時計回りのときー>1
if(cross(b,c)>eps)return 1;
//時計回りのときー>-1
if(cross(b,c)<-eps)return -1;
//c,a,bがこの順で同一直線上にあるとき
if(dot(b,c)<0)return 2;
//a,b,cがこの順で同一直線上にあるとき
if(norm(b)<norm(c))return -2;
//cが線分ab上にあるとき
return 0;
}
//Line:直線
//b-aで直線・線分
struct Line{
point a,b;
Line()=default;
Line(point a, point b) : a(a),b(b){}
//ax+by=c
Line(ld A, ld B, ld C){
if(equal(A,0)){
a=point(0,C/B),b=point(1,C/B);
}else if(equal(B,0)){
b=point(C/A,0),b=point(C/A,1);//ホントにb⁇
}else{
a=point(0,C/B),b=point(C/A,0);
}
}
};
//線分
struct Segment : Line{
Segment()=default;
Segment(point a, point b):Line(a,b){}
ld get_dist(){return abs(a-b);}
};
//円
//pが中心の位置ベクトル,rは半径
struct circle{
point p;
ld r;
circle()=default;
circle(point p, ld r) : p(p),r(r){};
};
//2直線の直交判定 内積0
bool isOrthogonal(const Line &a, const Line &b){
return equal(dot(a.b-a.a,b.b-b.a),0);
}
//2直線の平行判定 外積0
bool isParaleel(const Line &a, const Line &b){
return equal(cross(a.b-a.a,b.b-b.a),0);
}
//点cが直線ab上にあるか
bool isPointOnLine(const point &a,const point &b, const point &c){
return isParaleel(Line(a,b),Line(a,c));
}
//点cが線分ab上にあるか
bool isPointOnSegment(const point &a, const point &b, const point &c){
//|a-c|+|c-b|<=|a-b|なら線分上
return (abs(a-c)+abs(c-b)<abs(a-b)+eps);
}
//直線lと点pのキョリ
ld distanceBetweenLineAndPoint(const Line &l, const point &p){
return abs(cross(l.b-l.a,p-l.a))/abs(l.b-l.a);
}
//線分lと点pのキョリを求める
//点pから線分lのどこかへの最短距離
ld distanceBetweenSegmentAndPoint(const Segment &l, const point &p){
if(dot(l.b-l.a,p-l.a)<eps)return abs(p-l.a);
if(dot(l.a-l.b,p-l.b)<eps)return abs(p-l.b);
return abs(cross(l.b-l.a,p-l.a))/abs(l.b-l.a);
}
//直線s,tの交点
point crossPoint(const Line &s, const Line &t){
ld d1=cross(s.b-s.a,t.b-t.a);
ld d2=cross(s.b-s.a,s.b-t.a);
if(equal(abs(d1),0) and equal(abs(d2),0))return t.a;
return t.a+(t.b-t.a)*(d2/d1);
}
//線分s,tの交点
point crossPoint(const Segment &s,const Segment &t){
return crossPoint(Line(s),Line(t));
}
//線分sと線分tが交差しているか
//bound:線分の境界を含むか
bool isIntersect(const Segment &s, const Segment &t, bool bound){
return ccw(s.a,s.b,t.a)*ccw(s.a,s.b,t.b)<bound and
ccw(t.a,t.b,s.a)*ccw(t.a,t.b,s.b)<bound;
}
//線分s,t間のキョリ
ld distanceBetweenSegments(const Segment &s,const Segment &t){
if(isIntersect(s,t,1))return (ld)(0);
ld ans=distanceBetweenSegmentAndPoint(s,t.a);
ans=min(ans,distanceBetweenSegmentAndPoint(s,t.b));
ans=min(ans,distanceBetweenSegmentAndPoint(t,s.a));
ans=min(ans,distanceBetweenSegmentAndPoint(t,s.b));
return ans;
}
//射影(projection)
//直線(線分)lに点pから引いた垂線の足を求める
point projection(const Line &l, const point &p){
ld t=dot(p-l.a,l.a-l.b)/norm(l.a-l.b);
return l.a+(l.a-l.b)*t;
}
point projection(const Segment &l, const point &p){
ld t=dot(p-l.a,l.a-l.b)/norm(l.a-l.b);
return l.a+(l.a-l.b)*t;
}
//反射(reflection)
//直線lを対象軸として点pと線対称の位置にある点
point reflection(const Line &l, const point &p){
return p+(projection(l,p)-p)*(ld)2.0;
}
//2円の交差判定
//返り値は共通接戦の数
int isIntersect(const circle &c1, const circle &c2){
ld d=abs(c1.p-c2.p);
//2円が離れているとき
if(d>c1.r+c2.r+eps)return 4;
//外接しているとき
if(equal(d,c1.r+c2.r))return 3;
//内接しているとき
if(equal(d,abs(c1.r-c2.r)))return 1;
//内包しているとき
if(d<abs(c1.r-c2.r)-eps)return 0;
return 2;
}
//2円の交点
vector<point> crossPoint(const circle &c1, const circle &c2){
vector<point>ret;
int mode=isIntersect(c1,c2);
//2円の中心間のキョリ
ld d=abs(c1.p-c2.p);
//2円が離れているとき
if(mode==4)return ret;
//一方の円が他方の円に内包されているとき
if(mode==0)return ret;
//2円が外接するとき
if(mode==3){
ld t=c1.r/(c1.r+c2.r);
ret.emplace_back(c1.p+(c2.p-c1.p)*t);
return ret;
}
//内接しているとき
if(mode==1){
if(c2.r<c1.r-eps){
ret.emplace_back(c1.p+(c2.p-c1.p)*(c1.r/d));
}else{
ret.emplace_back(c2.p+(c1.p-c2.p)*(c2.r/d));
}
return ret;
}
//2円が重なるとき
ld rc1=(c1.r*c1.r+d*d-c2.r*c2.r)/(2*d);
ld rs1=sqrt(c1.r*c1.r-rc1*rc1);
if(c1.r-abs(rc1)<eps)rs1=0;
point e12=(c2.p-c1.p)/abs(c2.p-c1.p);
ret.emplace_back(c1.p+rc1*e12+rs1*e12*point(0,1));
ret.emplace_back(c1.p+rc1*e12+rs1*e12*point(0,-1));
return ret;
}
//点pが円cの内部(円周上も含む)に入っているかどうか
bool isIncircle(const circle &c, const point &p){
ld d=abs(c.p-p);
return (equal(d,c.r) or d<c.r-eps);
}
//円cと直線lの交点
vector<point> crossPoint(const circle &c, const Line &l){
vector<point> ret;
ld d=distanceBetweenLineAndPoint(l,c.p);
//交点を持たない
if(d>c.r+eps)return ret;
//接する
point h=projection(l,c.p);
if(equal(d,c.r)){
ret.emplace_back(h);
return ret;
}
point e=unitVector(l.b-l.a);
ld ph=sqrt(c.r*c.r-d*d);
ret.emplace_back(h-e*ph);
ret.emplace_back(h+e*ph);
return ret;
}
//点pを通る円cの接線
//2本あるので接点のみを返す
vector<point> tangentToCircle(const point &p, const circle &c){
return crossPoint(c,circle(p,sqrt(norm(c.p-p)-c.r*c.r)));
}
//円の共通接線
vector<Line> tangent(const circle &a, const circle &b){
vector<Line>ret;
//2円の中心間のキョリ
ld g=abs(a.p-b.p);
if(equal(g,0))return ret;
point u=unitVector(b.p-a.p);
point v=rotate(u,PI/2);
for(int s : {-1,1}){
ld h=(a.r+b.r*s)/g;
if(equal(h*h,1)){
ret.emplace_back(a.p+(h>0 ? u:-u)*a.r,
a.p+(h>0 ? u:-u)*a.r+v);
}else if(1-h*h>0){
point U=u*h,W=v*sqrt(1-h*h);
ret.emplace_back(a.p+(U+W)*a.r,
b.p-(U+W)*(b.r*s));
ret.emplace_back(a.p+(U-W)*a.r,
b.p-(U-W)*(b.r*s));
}
}
return ret;
}
//多角形の面積を求める
ld polygonArea(const vector<point> &p){
ld ret=0;
int n=p.size();
for(int i=0; i<n-1; i++)ret+=cross(p[i],p[i+1]);
ret+=cross(p[n-1],p[0]);
return ret*0.5;
}
//凸多角形かどうか
bool isConvex(const vector<point> &p){
int n=p.size();
int now,pre,nxt;
for(int i=0;i<n;i++){
pre=(i-1+n)%n;
nxt=(i+1)%n;
now=i;
if(ccw(p[pre],p[now],p[nxt])==-1)return false;
}
return true;
}
//凸包O(NlogN)
vector<point> ConvexHull(vector<point> p){
int n=(int)p.size(),k=0;
sort(p.begin(),p.end(),[](const point &a, const point &b){
return (a.real()!=b.real() ? a.real()<b.real() : a.imag()<b.imag());
});
vector<point> ch(2*n);
//一直線上の3点を含める->(<eps)
//含めない->(<eps)
for(int i=0; i<n; ch[k++]=p[i++]){
while(k>=2 and
cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<eps)k--;
}
for(int i=n-2,t=k+1;i>=0;ch[k++]=p[i--]){
while(k>=t and
cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<eps)k--;
}
ch.resize(k-1);
return ch;
}
//多角形gに点pが含まれているか
//含まれる:2,辺上にある:1,含まれない:0
int isContained(const vector<point> &g, const point &p){
bool in =false;
int n=(int)g.size();
for(int i=0;i<n;i++){
point a=g[i]-p,b=g[(i+1)%n]-p;
if(imag(a)>imag(b))swap(a,b);
if(imag(a)<=eps and eps<imag(b) and cross(a,b)<-eps)in=!in;
if(cross(a,b)==0 and dot(a,b)<=0)return 1;
}
return (in ? 2 : 0);
}
// 凸多角形pを直線lで切断し、その左側を返す
vector<point> convexCut(vector<point> p, Line l){
vector<point> ret;
int sz=(int)p.size();
for(int i=0;i<sz;i++){
point now=p[i];
point nxt=p[i==sz-1 ? 0 : i+1];
if(ccw(l.a,l.b,now)!=-1)ret.emplace_back(now);
if(ccw(l.a,l.b,now)*ccw(l.a,l.b,nxt)<0){
ret.emplace_back(crossPoint(Line(now,nxt),l));
}
}
return ret;
}
}
using namespace geometry;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<point> p(n);
rep(i,n){
int a,b;
cin >> a >> b;
p[i].real(a);
p[i].imag(b);
}
auto e=ConvexHull(p);
if(e.size()==n)cout << yes << endl;
else cout << no << endl;
}