結果
| 問題 |
No.2620 Sieve of Coins
|
| コンテスト | |
| ユーザー |
startcpp
|
| 提出日時 | 2023-12-15 01:02:35 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
AC
|
| 実行時間 | 798 ms / 2,000 ms |
| コード長 | 4,145 bytes |
| コンパイル時間 | 227 ms |
| コンパイル使用メモリ | 82,180 KB |
| 実行使用メモリ | 95,376 KB |
| 最終ジャッジ日時 | 2024-09-27 05:52:58 |
| 合計ジャッジ時間 | 15,359 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 5 |
| other | AC * 53 |
ソースコード
from typing import List, Dict, Tuple
def setMebius(n: int) -> List[int]:
is_prime: List[int] = [True] * (n + 1)
mebius: List[int] = [1] * (n + 1)
is_prime[0] = False
is_prime[1] = False
for i in range(2, n + 1):
if is_prime[i]:
bai: int = 0 if i == 2 else 2
mebius[i] *= -1
for j in range(2 * i, n + 1, i):
is_prime[j] = False
if bai == 0:
mebius[j] = 0
else:
mebius[j] *= -1
bai += 1
if bai == i:
bai = 0
return mebius
def calc(L: int, noDiv2: bool, noDiv3: bool, mebius: List[int]) -> int:
ret: int = 0
i: int = 1
while i * i <= L:
keisu: int = 0 # g(i) := L以下の正のi * iの倍数であって「noDiv*=trueなら*の倍数でない」を満たすものの個数
if i % 2 == 0 and noDiv2:
keisu = 0
elif i % 3 == 0 and noDiv3:
keisu = 0
else:
c: int = L // (i * i)
keisu = c
if noDiv2:
keisu -= c // 2
if noDiv3:
keisu -= c // 3
if noDiv2 and noDiv3:
keisu += c // 6
# f(i) := L以下の正のi * iの倍数であって「noDiv*=trueなら*の倍数でない」を満たす上で、任意の整数j > iについてj * jの倍数でもないものの個数
# f(i) = g(i) - f(2 * i) - f(3 * i) - f(4 * i) - ...より、g(i) = sum(i|j, f(j)) (jはiの倍数)
# メビウスの反転公式より f(i) = sum(i|j, μ(j/i) g(j)). 求めたいのはf(1)なので、f(1) = sum(j, μ(j)g(j)) が得られる.
ret += mebius[i] * keisu
i += 1
return ret
def subtask4(L: int, a: List[int], mebius: List[int]) -> int:
n: int = len(a)
plot: List[List[bool]] = [[False for _ in range(60)] for _ in range(60)]
for i in range(n):
c2: int = 0
c3: int = 0
t: int = a[i]
while t % 2 == 0:
t //= 2
c2 += 1
while t % 3 == 0:
t //= 3
c3 += 1
plot[c2][c3] = True
p2: List[int] = [1]
p3: List[int] = [1]
while p2[-1] <= L:
p2.append(p2[-1] * 2)
while p3[-1] <= L:
p3.append(p3[-1] * 3)
ret: int = 0
i: int = 0
mp: Dict[Tuple[int, int, int], int] = {}
while p2[i] <= L:
j: int = 0
while p2[i] * p3[j] <= L:
tmpL: int = L // (p2[i] * p3[j]) # 選ぶ要素のLCM = p2[i] * p3[j]
for k in range(16):
max2: int = -1
min2: int = 1000000
max3: int = -1
min3: int = 1000000
cnt: int = 0
not_found: bool = False
for l in range(4):
if (k >> l) % 2 == 1:
c2: int = i - l // 2
c3: int = j - l % 2
if c2 < 0 or c3 < 0 or plot[c2][c3] == False:
not_found = True
break
max2 = max(max2, c2)
min2 = min(min2, c2)
max3 = max(max3, c3)
min3 = min(min3, c3)
cnt += 1
if not_found or cnt == 0 or max2 != i or max3 != j:
continue
noDiv2 = (min2 != max2)
noDiv3 = (min3 != max3)
key = (tmpL, noDiv2, noDiv3)
if key not in mp:
mp[key] = calc(tmpL, noDiv2, noDiv3, mebius)
if cnt % 2 == 1:
ret += mp[key] * p2[cnt - 1]
else:
ret -= mp[key] * p2[cnt - 1]
j += 1
i += 1
return ret
if __name__ == '__main__':
L, N = map(int, input().split())
a = list(map(int, input().split()))
sqL: int = 1
while sqL * sqL <= L:
sqL += 1
sqL -= 1
mebius: List[int] = setMebius(sqL)
ans: int = subtask4(L, a, mebius)
print(ans)
startcpp