結果
| 問題 | No.947 ABC包囲網 |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-12-18 00:12:15 |
| 言語 | C# (.NET 10.0.101) |
| 結果 |
AC
|
| 実行時間 | 479 ms / 2,000 ms |
| コード長 | 4,908 bytes |
| 記録 | |
| コンパイル時間 | 9,198 ms |
| コンパイル使用メモリ | 169,768 KB |
| 実行使用メモリ | 194,028 KB |
| 最終ジャッジ日時 | 2025-12-18 00:12:42 |
| 合計ジャッジ時間 | 23,723 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 60 |
コンパイルメッセージ
復元対象のプロジェクトを決定しています... /home/judge/data/code/main.csproj を復元しました (120 ミリ秒)。 main -> /home/judge/data/code/bin/Release/net8.0/main.dll main -> /home/judge/data/code/bin/Release/net8.0/publish/
ソースコード
using System;
using static System.Console;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.Intrinsics.Arm;
class Program
{
static int NN => int.Parse(ReadLine());
static int[] NList => ReadLine().Split().Select(int.Parse).ToArray();
static int[][] NArr(long n) => Enumerable.Repeat(0, (int)n).Select(_ => NList).ToArray();
public static void Main()
{
Solve();
}
static void Solve()
{
var n = NN;
var p = NArr(n);
var list = new List<Point>(n);
for (var i = 0; i < n; ++i) list.Add(new Point(p[i][0], p[i][1]));
list.Sort();
var ans = 0L;
var ublist = new int[n];
var lblist = new int[n];
for (var i = 0; i < n; ++i)
{
var revi = GetReverse(list[i]);
ublist[i] = UpperBound(revi, list) % n;
lblist[i] = LowerBound(revi, list) % n;
}
for (var i = 0; i < n; ++i) for (var j = i + 1; j < n; ++j)
{
if (list[i].CompareTo(list[j]) == 0) continue;
var revi = GetReverse(list[i]);
if (revi.CompareTo(list[j]) == 0) continue;
var revj = GetReverse(list[j]);
if (OuterProduct(revi.X, revi.Y, revj.X, revj.Y) > 0)
{
var posri = ublist[i];
var posrj = lblist[j];
if (posri <= posrj) ans += posrj - posri;
else ans += posrj + n - posri;
}
else
{
var posrj = ublist[j];
var posri = lblist[i];
if (posrj <= posri) ans += posri - posrj;
else ans += posri + n - posrj;
}
// if (revj.CompareTo(list[posrj]) != 0) --ans;
}
WriteLine(ans / 3);
}
static Point GetReverse(Point b)
{
return new Point(-b.X, -b.Y, b.Dx, b.Dy, (b.Dim + 4) % 8);
}
class Point : IComparable<Point>
{
public int X;
public int Y;
public int Dx;
public int Dy;
public int Dim;
public Point(int x, int y)
{
X = x; Y = y;
(Dx, Dy, Dim) = GetRad(x, y);
}
public Point(int x, int y, int dx, int dy, int dim)
{
X = x; Y = y; Dx = dx; Dy = dy; Dim = dim;
}
public int CompareTo(Point b)
{
var d = Dim.CompareTo(b.Dim);
if (d != 0) return d;
if (Dim % 2 == 0) return 0;
d = ((long)b.Dx * Dy).CompareTo((long)Dx * b.Dy);
if (Dim % 4 == 1) return d;
else return -d;
}
public override string ToString()
{
return $"({X}, {Y})";
}
}
// 角度を求める
// dx,dy: 有理数の角度(絶対値)
// dim: 象限 (0: X軸正, 1: X>0,Y>0, 2: Y軸正, 3: X<0,Y>0, 4: X軸負, 5: X<0,Y<0, 6: Y軸負, 7: X>0,Y<0)
static (int dx, int dy, int dim) GetRad(int x, int y)
{
if (x == 0)
{
if (y > 0) return (0, 1, 2);
if (y < 0) return (0, 1, 6);
throw new Exception("原点");
}
if (y == 0)
{
if (x > 0) return (1, 0, 0);
if (x < 0) return (1, 0, 4);
}
var gcd = GCD(Math.Abs(x), Math.Abs(y));
if (x > 0 && y > 0)
{
return (x / gcd, y / gcd, 1);
}
else if (y > 0)
{
return (-x / gcd, y / gcd, 3);
}
else if (x > 0)
{
return (x / gcd, -y / gcd, 7);
}
return (-x / gcd, -y / gcd, 5);
}
static int GCD(int a, int b)
{
if (a < b) return GCD(b, a);
if (a % b == 0) return b;
return GCD(b, a % b);
}
static int LowerBound<T>(T min, IList<T> list) where T: IComparable<T>
{
var ng = -1;
var ok = list.Count;
while (ok - ng > 1)
{
var mid = (ng + ok) / 2;
if (list[mid].CompareTo(min) < 0) ng = mid;
else ok = mid;
}
return ok;
}
static int UpperBound<T>(T min, IList<T> list) where T: IComparable<T>
{
var ng = -1;
var ok = list.Count;
while (ok - ng > 1)
{
var mid = (ng + ok) / 2;
if (list[mid].CompareTo(min) <= 0) ng = mid;
else ok = mid;
}
return ok;
}
/// 外積(Z=0としたとき)を求める
/// 正ならベクトルBはベクトルAの進行方向左側にある
/// 0なら方向一致、負なら右側
static long OuterProduct(int ax, int ay, int bx, int by)
{
return (long)ax * by - (long)ay * bx;
}
}