結果
| 問題 | No.288 貯金箱の仕事 |
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:03:42 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 8,220 bytes |
| コンパイル時間 | 435 ms |
| コンパイル使用メモリ | 82,664 KB |
| 実行使用メモリ | 83,712 KB |
| 最終ジャッジ日時 | 2025-05-14 13:05:34 |
| 合計ジャッジ時間 | 26,232 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 48 WA * 2 TLE * 3 |
ソースコード
import heapq
import math
import sys
# Use fast I/O
input = sys.stdin.readline
def solve():
# Read input values N and M
N, M_str = input().split()
N = int(N)
M = int(M_str) # M can be large, up to 10^18
# Read coin denominations A_1, ..., A_N
A_str = input().split()
A = [int(a) for a in A_str] # A_i up to 500
# Read initial coin counts K_1, ..., K_N
K_str = input().split()
K = [int(k) for k in K_str] # K_i up to 10^12
# Calculate the total value Yukiusagi initially possesses
current_total_value = 0
for i in range(N):
# Calculations involve large integers, Python handles this automatically
current_total_value += K[i] * A[i]
# The problem transforms into a change-making problem.
# We need to find the minimum number of coins to make change for value M' = sum(K_i A_i) - M.
# Let target_val = M'.
target_val = current_total_value - M
# If target_val is negative, it means Yukiusagi doesn't have enough value M to begin with.
# The transaction is impossible.
if target_val < 0:
print("-1")
return
# If target_val is zero, it means Yukiusagi has exactly M value more than needed.
# She pays M, using all her coins? No, she needs to pay exactly M net.
# If target_val = 0, this means sum K_i A_i = M. Yukiusagi can pay M using all her coins.
# In the transformed problem, we need to make change for M'=0. Minimum coins is 0.
if target_val == 0:
print("0")
return
# Calculate the greatest common divisor (GCD) of all coin denominations.
g = A[0]
for i in range(1, N):
g = math.gcd(g, A[i])
# The net amount M must be payable. Any payable amount must be a multiple of the GCD.
# If M is not divisible by g, the transaction is impossible.
if M % g != 0:
print("-1")
return
# Also, the target value M' must be formable using the available coins.
# This implies M' must also be divisible by g.
# Check: M' = sum K_i A_i - M. Since each A_i is divisible by g, sum K_i A_i is divisible by g.
# If M is divisible by g, then M' = (multiple of g) - (multiple of g), which is also a multiple of g.
# If M is not divisible by g, then M' = (multiple of g) - (not multiple of g), which is not multiple of g.
# So the check M % g != 0 already covers the condition for M'. We add an explicit check for safety.
if target_val % g != 0:
print("-1")
return
# Use the largest coin denomination A_N as the base for the Dijkstra algorithm modulus.
# The problem states A is sorted: A_1 < A_2 < ... < A_N.
A_N = A[N-1]
# For the change-making problem (minimum coins for target_val), we use a hybrid approach:
# 1. Standard dynamic programming for small target values.
# 2. Dijkstra on remainders modulo A_N for large target values.
# Define a bound B to switch between DP and Dijkstra. A safe bound is related to A_N^2.
# Let's use B = 2 * A_N^2.
max_A = A_N
# The bound calculation can result in a large number, Python handles this.
bound_B = 2 * max_A * max_A
# Handle the edge case N=1 separately.
if N == 1:
# Only one type of coin A[0]. Change making is simple division.
if target_val % A[0] == 0:
# Result is target_val / A[0] coins.
print(target_val // A[0])
else:
# Cannot make exact change.
print("-1")
return
# Use float('inf') for representing infinity. Comparisons work correctly with large integers.
INF = float('inf')
# If target_val is small (<= bound_B), use DP.
if target_val <= bound_B:
# `target_val` can be large, ensure `dp_limit` fits standard integer range if needed.
# In Python, list indexing with large integers is okay.
dp_limit = int(target_val)
dp_small = [INF] * (dp_limit + 1)
dp_small[0] = 0 # Base case: 0 value requires 0 coins.
# Fill DP table
for v in range(1, dp_limit + 1):
for coin in A: # Iterate through available coin denominations
if v >= coin and dp_small[v - coin] != INF:
# Update minimum coins needed for value v
dp_small[v] = min(dp_small[v], 1 + dp_small[v - coin])
final_coins = dp_small[dp_limit]
if final_coins == INF:
# target_val cannot be formed.
print("-1")
else:
# Print the minimum number of coins found by DP.
print(int(final_coins)) # Ensure output is integer
return
# If target_val is large (> bound_B), use Dijkstra on remainders modulo A_N.
# `min_cost_for_rem[r]` stores the minimum number of coins found so far for *some* value V s.t. V % A_N == r.
# `min_val_at_min_cost[r]` stores the minimum value V that achieved this minimum cost.
min_cost_for_rem = {}
min_val_at_min_cost = {}
# Initialize distances/costs to infinity for all remainders.
for r in range(A_N):
min_cost_for_rem[r] = INF
min_val_at_min_cost[r] = INF
# Initialize state for remainder 0: 0 cost, 0 value.
min_cost_for_rem[0] = 0
min_val_at_min_cost[0] = 0
# Priority queue for Dijkstra. Stores tuples: (cost, value, remainder).
# Python's heapq implements a min-heap.
pq_actual = [(0, 0, 0)]
while pq_actual:
# Pop the state with the lexicographically smallest (cost, value) pair.
cost, value, rem = heapq.heappop(pq_actual)
# If we've found a better path to this remainder state already, skip.
if cost > min_cost_for_rem[rem] or (cost == min_cost_for_rem[rem] and value > min_val_at_min_cost[rem]):
continue
# Explore neighbors by trying to add each coin type.
for i in range(N):
curr_A = A[i]
# Calculate next state's remainder, cost, and value.
next_rem = (rem + curr_A) % A_N
next_cost = cost + 1
next_value = value + curr_A
# If this path leads to a better state (lexicographically smaller cost, value pair)
# for `next_rem`, update and push to priority queue.
if next_cost < min_cost_for_rem[next_rem] or \
(next_cost == min_cost_for_rem[next_rem] and next_value < min_val_at_min_cost[next_rem]):
min_cost_for_rem[next_rem] = next_cost
min_val_at_min_cost[next_rem] = next_value
heapq.heappush(pq_actual, (next_cost, next_value, next_rem))
# After Dijkstra, find the result for target_val based on its remainder.
target_rem = target_val % A_N
# Check if the target remainder is reachable.
if min_cost_for_rem[target_rem] == INF:
# If unreachable, target_val cannot be formed.
print("-1")
return
# Get the base cost and base value found by Dijkstra for target_rem.
base_cost = min_cost_for_rem[target_rem]
base_val = min_val_at_min_cost[target_rem]
# Critical check: target_val must be at least the minimum value found for its remainder path.
# If target_val < base_val, it means target_val cannot be formed by adding A_N coins
# to the base value `base_val`. Based on theory, this implies impossibility for large values.
if target_val < base_val:
print("-1")
return
# Calculate the difference that needs to be covered by A_N coins.
diff = target_val - base_val
# Safety check: The difference must be non-negative and divisible by A_N.
# This should hold true based on the logic, but check for robustness.
if diff < 0 or diff % A_N != 0:
# This indicates an unexpected state or logical error. Output -1 for impossibility.
print("-1")
return
# Calculate the number of A_N coins needed.
num_AN_coins = diff // A_N
# Total minimum coins = base cost from Dijkstra + number of A_N coins.
total_coins = base_cost + num_AN_coins
# Print the final result.
print(int(total_coins)) # Ensure output is integer
# Execute the solve function
solve()
qwewe