Official

D - タイル張りの計画 / Tiling Plan Editorial by kyopro_friends


大きさ \(d\) のタイルで全ての部屋を敷き詰められることは、\(d\) が全ての \(i\) で \(H_i,W_i\) の約数であることと同値です。よってこの条件は、\(d\) が \(\gcd(H_1,\dots,H_N,W_1,\dots,W_N)\) の約数であることと同値です。

部屋 \(i\) を敷き詰めるタイルの枚数が \(S_i\) の倍数であることは、「ある整数 \(k\) が存在して \(\frac{H_iW_i}{d^2}=kS_i\) となること」であり、 \(S_i\) が \(H_iW_i\) の約数であることからこれは「ある整数 \(k\) が存在して \(\frac{H_iW_i}{S_i}=kd^2\) となること」、即ち「\(d^2\) が \(\frac{H_iW_i}{S_i}\) の約数であること」と同値です。よって、全ての \(i\) でこれが成り立つことは「\(d^2\) が \(\gcd(\frac{H_1W_1}{S_1},\dots,\frac{H_NW_N}{S_N})\) の約数であること」と同値です。

以上より

  • \(d\) は \(\gcd(H_1,\dots,H_N,W_1,\dots,W_N)\) の約数
  • \(d^2\) は \(\gcd(\frac{H_1W_1}{S_1},\dots,\frac{H_NW_N}{S_N})\) の約数

の 2 条件が必要十分であることがわかりました。

\(M=\max(H_1,\dots,H_N,W_1,\dots,W_N)\) として、 gcd の計算に \(O(N+\log M)\) 、 1 番目の条件を満たす \(d\) の列挙に \(O(\sqrt{M})\) 、それらそれぞれに対して 2 番目の条件を満たすか判定するのに各 \(O(1)\) であることから、 \(O(N+\sqrt{M})\) で答えを求めることができます。

実装例 (C++)

#include<bits/stdc++.h>
using namespace std;

int main(){
  int g1 = 0;
  long long g2 = 0;
  
  int n;
  cin >> n;
  for(int i=0; i<n; i++){
    int h, w, s;
    cin >> h >> w >> s;
    g1 = __gcd(g1, __gcd(h, w));
    g2 = __gcd(g2, (long long)h*w/s);
  }
  
  vector<int> d;
  for(int i=1; i*i<=g1; i++){
    if(g1 % i == 0){
      d.push_back(i);
      d.push_back(g1/i);
    }
  }
  
  int ans = 1;
  for(auto x: d){
    if(g2 % ((long long)x*x) == 0){
      ans = max(ans, x);
    }
  }
  cout << ans << endl;
}

実装例 (Python)

import math

g1 = 0
g2 = 0
N = int(input())
for _ in range(N):
  H, W, S = map(int, input().split())
  g1 = math.gcd(g1, H, W)
  g2 = math.gcd(g2, H*W//S)

d=[]
for i in range(1, math.isqrt(g1)+1):
  if g1 % i == 0:
    d.append(i)
    d.append(g1//i)

print(max(x for x in d if g2 % (x*x) == 0))

posted:
last update: