結果

問題 No.947 ABC包囲網
コンテスト
ユーザー kakel-san
提出日時 2025-12-18 00:12:15
言語 C#
(.NET 10.0.101)
結果
AC  
実行時間 479 ms / 2,000 ms
コード長 4,908 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 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/

ソースコード

diff #
raw source code

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;
    }
}
0