結果
問題 |
No.719 Coprime
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:20:23 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 8,232 bytes |
コンパイル時間 | 1,341 ms |
コンパイル使用メモリ | 81,944 KB |
実行使用メモリ | 272,452 KB |
最終ジャッジ日時 | 2025-05-14 13:21:43 |
合計ジャッジ時間 | 16,452 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 52 TLE * 1 -- * 8 |
ソースコード
import sys import math # Set a higher recursion depth limit. The problem constraints might lead to deep recursion. # N up to 1262 means the maximum number of odd numbers is about 630. # The recursion depth could potentially reach this value in the worst case. # We set it to 2000 to be safe. try: sys.setrecursionlimit(2000) except Exception as e: # In some environments, setting recursion depth might fail. # We print a warning to stderr but continue. The default limit might be sufficient. # print(f"Warning: Could not set recursion depth: {e}", file=sys.stderr) # Commented out for final submission pass # Memoization dictionary to store results of computed subproblems. # Keys will be tuples representing sorted subsets of candidate numbers. memo = {} # Adjacency list to represent the conflict graph. # An edge exists between two numbers if their greatest common divisor (GCD) is greater than 1. adj_all = {} # Function to build the adjacency list `adj_all` for numbers from 2 to N. def build_adj(N): """Builds the adjacency list for numbers 2 to N based on gcd > 1.""" # Create a list of numbers from 2 to N. nums = list(range(2, N + 1)) # Initialize an empty list for each number in the adjacency list dictionary. for x in nums: adj_all[x] = [] # Iterate through all unique pairs of numbers (i, j) where i < j. for i in range(len(nums)): for j in range(i + 1, len(nums)): # Calculate the greatest common divisor (GCD) of the pair. # Use Python's built-in math.gcd for efficiency. if math.gcd(nums[i], nums[j]) > 1: # If GCD > 1, they conflict. Add an edge between them in the graph. adj_all[nums[i]].append(nums[j]) adj_all[nums[j]].append(nums[i]) # Recursive function to find the Maximum Weight Independent Set (MWIS). # Uses backtracking with memoization. # `candidates_tuple` must be a tuple of candidate numbers, sorted in ascending order. def max_weight_independent_set(candidates_tuple): """Computes the maximum weight independent set sum for a given tuple of candidates.""" # Base case: If there are no candidates left, the sum is 0. if not candidates_tuple: return 0 # Use the sorted tuple of candidates as the state key for memoization. # This ensures that the same subset of candidates, regardless of order arrived, # maps to the same state. state = candidates_tuple if state in memo: # If this state has been computed before, return the cached result. return memo[state] # Branching step: Choose a vertex to make a decision on (include or exclude). # Strategy: Pick the vertex with the largest value. Since the tuple is sorted, # this is the last element. This heuristic can sometimes prune the search faster. k = candidates_tuple[-1] # Convert the tuple to a set for efficient membership checking and element removal. candidates_set = set(candidates_tuple) # --- Option 1: Include vertex k in the independent set --- # If k is included, we cannot include any of its neighbors. # Find neighbors of k that are present in the current set of candidates. neighbors_of_k_in_candidates = [] # Check if k has any neighbors recorded in the full adjacency list. # k should always be in adj_all since N >= 2 implies k >= 2 # Small optimization: check if k has neighbors before iterating if k in adj_all and adj_all[k]: for neighbor in adj_all[k]: # Check if this neighbor is among the current candidates. if neighbor in candidates_set: neighbors_of_k_in_candidates.append(neighbor) # Create the set of remaining candidates for the recursive call when k is included: # Start with a copy of the current candidates set. remaining_candidates1_set = candidates_set.copy() # Remove k itself. remaining_candidates1_set.remove(k) # Remove all neighbors of k found within the current candidates set. for neighbor in neighbors_of_k_in_candidates: # Need to check if neighbor is still in the set, as it might have been removed if it was equal to k # (not possible here since k != neighbor) or if it was also a neighbor of a previously removed node # (not applicable in this step, but good practice for general MWIS). # More simply, check if it's present before removing to avoid errors. if neighbor in remaining_candidates1_set: remaining_candidates1_set.remove(neighbor) # Recursively call the function for the remaining candidates. # The result for this branch is k (value of included vertex) plus the result of the subproblem. # Pass the remaining candidates as a sorted tuple to maintain canonical state representation. sum1 = k + max_weight_independent_set(tuple(sorted(list(remaining_candidates1_set)))) # --- Option 2: Exclude vertex k from the independent set --- # If k is excluded, we simply remove k and proceed with the rest of the candidates. # Create the set of remaining candidates for the recursive call when k is excluded. remaining_candidates2_set = candidates_set.copy() remaining_candidates2_set.remove(k) # Recursively compute the max weight sum for this subset. # Pass the remaining candidates as a sorted tuple. sum2 = max_weight_independent_set(tuple(sorted(list(remaining_candidates2_set)))) # --- Combine results --- # The maximum weight for the current state is the maximum of the two options: including k or excluding k. result = max(sum1, sum2) # Store the computed result in the memoization table before returning. memo[state] = result return result # Main function to coordinate the solving process. def solve(): """Reads input N, orchestrates the MWIS computation, and prints the final result.""" # Read integer N from standard input. N = int(sys.stdin.readline()) # Handle the base case N=2 where the only card is 2. Max sum is 2. if N == 2: print(2) return # Precompute the adjacency list representing conflicts (GCD > 1). build_adj(N) # Partition the numbers from 2 to N into even and odd lists. # This is key because at most one even number can be in a valid set (due to factor 2). evens = [] odds = [] for x in range(2, N + 1): if x % 2 == 0: evens.append(x) else: odds.append(x) # Clear the memoization cache before starting the main computation phase. memo.clear() # Case 1: The maximum sum is achieved using only odd numbers. # Compute the MWIS sum for the set of all odd numbers. odds_tuple = tuple(sorted(odds)) # Use sorted tuple for canonical state representation. max_sum_odds_only = max_weight_independent_set(odds_tuple) # Initialize the overall maximum sum found so far with this value. max_total_sum = max_sum_odds_only # Case 2: The maximum sum is achieved using exactly one even number `e` and a subset of compatible odd numbers. # Iterate through each even number `e`. for e in evens: # Identify the subset of odd numbers `O_e` that are coprime to `e` (i.e., gcd(e, o) == 1). O_e = [] for o in odds: if math.gcd(e, o) == 1: O_e.append(o) # Compute the MWIS sum for this compatible subset `O_e`. O_e_tuple = tuple(sorted(O_e)) # Use sorted tuple state. # Important: The memoization cache `memo` is shared across these calls. # If MWIS is computed for the same subset of odds multiple times (for different `e`), # the cached result is reused. current_max_sum_for_O_e = max_weight_independent_set(O_e_tuple) # Update the overall maximum sum if including `e` plus the best compatible odds subset sum # yields a higher total sum. max_total_sum = max(max_total_sum, e + current_max_sum_for_O_e) # Print the final maximum possible sum. print(max_total_sum) # Execute the main solver function when the script is run. solve()