Day 073-Q4 — 面積・Shoelace 公式・ピック定理・格子点多角形

2026-06-26 赤色 Master / Phase 8+ ★★★★★★★★★ Shoelace・Pick定理・gcd・格子点カウント

問題

$N$ 頂点の単純多角形(頂点は整数座標、自己交差なし)が与えられる。以下を求めよ:

  1. 面積: 多角形の面積(整数または半整数)
  2. 内部格子点数: 多角形の厳密な内部にある格子点の数(辺上は含まない)
  3. 辺上格子点数: 多角形の辺上にある格子点の数(頂点を含む)

制約

パラメータ範囲備考
$N$$3 \le N \le 10^5$頂点数
座標整数、$|x|, |y| \le 10^9$
格子点数$\le 10^{18}$

入出力例

入力例1(正方形)

4
0 0
5 0
5 5
0 5

出力例1

面積: 25
辺上格子点: 20
内部格子点: 16

入力例2(直角三角形)

3
0 0
4 0
0 3

出力例2

面積: 6
辺上格子点: 8
内部格子点: 3

概念図: Pick の定理

直角三角形 (0,0)-(4,0)-(0,3) の格子点 (4,0) (0,3) (0,0) 頂点 (3個) 辺上格子点 (B=8、頂点含む) 内部格子点 (I=3) Pick の定理 A = I + B/2 - 1 6 = 3 + 8/2 - 1 ✓ B = gcd(4,0)+gcd(3,0)+gcd(4,3) = 4+3+1 = 8

ヒント

ヒント1(方向性)
  • 面積: Shoelace 公式で $O(N)$、整数演算で誤差なし
  • 辺上格子点数 $B$: 各辺 $\gcd(|\Delta x|, |\Delta y|)$ の総和
  • 内部格子点数 $I$: Pick の定理 $I = A - B/2 + 1 = (2A - B + 2)/2$
ヒント2(アプローチ)
  1. Shoelace: $2A = |\sum_{i=0}^{N-1} (x_i y_{i+1} - x_{i+1} y_i)|$
  2. 辺上: $B = \sum_{i=0}^{N-1} \gcd(|x_{i+1}-x_i|, |y_{i+1}-y_i|)$
  3. Pick: $I = (2A - B + 2) // 2$
ヒント3(ほぼ答え)
from math import gcd

area2 = 0
for i in range(N):
    x1, y1 = pts[i]; x2, y2 = pts[(i+1)%N]
    area2 += x1*y2 - x2*y1
area2 = abs(area2)

B = sum(gcd(abs(pts[(i+1)%N][0]-pts[i][0]),
           abs(pts[(i+1)%N][1]-pts[i][1])) for i in range(N))

I = (area2 - B + 2) // 2

模範解答

import sys
from math import gcd
input = sys.stdin.readline

def solve():
    N = int(input())
    pts = [tuple(map(int, input().split())) for _ in range(N)]

    # Shoelace 公式で 2*面積 を計算(整数)
    area2 = 0
    for i in range(N):
        x1, y1 = pts[i]
        x2, y2 = pts[(i+1) % N]
        area2 += x1 * y2 - x2 * y1
    area2 = abs(area2)

    # 辺上格子点数 B
    B = 0
    for i in range(N):
        x1, y1 = pts[i]
        x2, y2 = pts[(i+1) % N]
        B += gcd(abs(x2-x1), abs(y2-y1))

    # Pick の定理: I = (2A - B + 2) / 2
    I = (area2 - B + 2) // 2

    if area2 % 2 == 0:
        area_str = str(area2 // 2)
    else:
        area_str = f"{area2 // 2}.5"

    print(f"面積: {area_str}")
    print(f"辺上格子点: {B}")
    print(f"内部格子点: {I}")

solve()

Step-by-Step 解説

Step 1: Shoelace(ガウスの面積)公式

$$2A = \left|\sum_{i=0}^{N-1} (x_i y_{i+1} - x_{i+1} y_i)\right|$$

各辺ベクトルの外積の総和の絶対値。整数座標なら誤差ゼロ。計算量 $O(N)$。

Step 2: 辺上の格子点数

線分 $(x_1, y_1) \to (x_2, y_2)$ 上の格子点数(両端含む)= $\gcd(|\Delta x|, |\Delta y|) + 1$。多角形全体では各辺の $\gcd$ を足す(隣接頂点を一度だけカウント)。

証明: $g = \gcd(dx, dy)$ とすると、方向ベクトル $(dx/g, dy/g)$ が最小ステップ。途中の格子点は $g-1$ 個(両端除く)。

Step 3: Pick の定理

$$A = I + \frac{B}{2} - 1 \implies I = \frac{2A - B + 2}{2}$$

$2A$ と $B$ はともに整数なので、$I$ が整数になることが保証される。

よくあるミス

ミス原因正しい書き方
area2 の符号が負時計回りの入力abs(area2) で絶対値
B のカウントで辺の両端を二重カウントgcd+1 を足すgcd(dx, dy) のみ足す
$I$ の整数性を確認しない非格子点多角形では成立しない整数座標多角形の前提を確認
gcd(0, 0) のエラー同一頂点の辺多角形では辺長 0 は起きない

次のステップ

  • 発展: 3D 多面体の体積と格子点数(Ehrhart 多項式)
  • 発展: 格子点多角形のラティス・バンドル
  • 発展: 非格子点多角形の面積最小化問題

自己評価

理解度:

自分の回答:

気づき・メモ: