結果

問題 No.1538 引きこもりさんは引き算が得意。
ユーザー qwewe
提出日時 2025-05-14 13:13:49
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
WA  
実行時間 -
コード長 8,999 bytes
コンパイル時間 949 ms
コンパイル使用メモリ 105,916 KB
実行使用メモリ 7,848 KB
最終ジャッジ日時 2025-05-14 13:14:38
合計ジャッジ時間 2,833 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 46 WA * 8
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <numeric> // Required for std::gcd (available since C++17)
#include <cmath>   // Required for std::abs
#include <unordered_map>
#include <vector>  // Make sure vector header is included

// Function to compute the greatest common divisor (GCD) of two numbers.
// Handles negative inputs by taking absolute values first.
// Relies on std::gcd available since C++17.
// If using an older standard, a custom implementation like Euclidean algorithm would be needed.
/*
long long custom_gcd(long long a, long long b) {
    a = std::abs(a);
    b = std::abs(b);
    while (b) {
        a %= b;
        std::swap(a, b);
    }
    return a;
}
*/

// Function to compute GCD of all elements in a vector A.
// Handles potential 0 values correctly. The GCD of a set containing 0 and some non-zero numbers
// is the GCD of the non-zero numbers. GCD involving only 0 is 0.
long long calculate_vec_gcd(const std::vector<long long>& A) {
    if (A.empty()) {
        return 0; // Define GCD of empty set as 0
    }
    long long res = 0; 
    for (long long x : A) {
        // std::gcd(a, 0) returns std::abs(a). This property helps compute GCD correctly.
        // It effectively initializes `res` with the absolute value of the first non-zero element 
        // and then computes GCD iteratively.
        res = std::gcd(res, std::abs(x)); 
    }
    // If all elements in A are 0, the result will be 0.
    // Otherwise, it's the GCD of the absolute values of the non-zero elements.
    return res;
}

// Global variables accessible by DFS functions
std::vector<long long> A; // Stores the input array A
int N;                    // Number of elements in A
long long K;              // The target value K
int N1;                   // Size of the first half of A (N / 2)

// map_L stores sums generated from the first half of A (indices 0 to N1-1).
// Key: a possible sum value.
// Value: a boolean flag. `true` if this sum can ONLY be formed using all zero coefficients
// (this is only possible if the sum itself is 0). `false` if this sum can be formed using
// at least one non-zero coefficient (+1 or -1).
std::unordered_map<long long, bool> map_L;

bool found = false; // Global flag set to true once a valid representation of K is found

// Depth First Search function to generate sums for the first half of array A.
// index: current element index being considered (from 0 up to N1-1).
// current_sum: the sum accumulated so far along the current path.
// all_zeros: boolean flag, true if all coefficients used so far on this path are 0.
void generate_sums_L(int index, long long current_sum, bool all_zeros) {
    // Base case: If we have considered all elements in the first half
    if (index == N1) { 
        // Check if this sum is already in the map
        auto it = map_L.find(current_sum);
        if (it == map_L.end()) {
            // If this sum value is encountered for the first time, insert it with its all_zeros flag.
            map_L[current_sum] = all_zeros;
        } else {
            // If this sum value already exists, update its flag.
            // The flag remains true only if BOTH the existing ways AND this new way use all_zeros.
            // If *any* path generating this sum used non-zero coefficients, the flag becomes false.
             it->second = it->second && all_zeros; 
        }
        return; // End this path of recursion
    }

    // Recursive calls for the next index (index + 1):
    // Option 1: Use coefficient 0 for A[index]. The 'all_zeros' state doesn't change.
    generate_sums_L(index + 1, current_sum, all_zeros); 

    // Option 2: Use coefficient +1 for A[index]. This path now uses a non-zero coefficient.
    generate_sums_L(index + 1, current_sum + A[index], false); 

    // Option 3: Use coefficient -1 for A[index]. This path also uses a non-zero coefficient.
    generate_sums_L(index + 1, current_sum - A[index], false); 
}

// Depth First Search function to generate sums for the second half of array A and check for matches.
// index: current element index being considered (from N1 up to N-1).
// current_sum: the sum accumulated so far for the second half along the current path.
// all_zeros_R: boolean flag, true if all coefficients used so far in the second half on this path are 0.
void generate_sums_R(int index, long long current_sum, bool all_zeros_R) {
    // Optimization: If a solution has already been found, stop exploring further paths.
    if (found) return; 

    // Base case: If we have considered all elements in the second half (reached index N)
    if (index == N) { 
        // Calculate the required sum from the first half to achieve the target K
        long long target_sum = K - current_sum; 
        
        // Check if this required sum (target_sum) exists in the map generated from the first half
        auto it = map_L.find(target_sum);
        if (it != map_L.end()) { 
            // If target_sum exists in map_L, get its associated all_zeros flag.
            bool all_zeros_L = it->second; 
            
            // A representation K = S1 + S2 is valid if it uses at least one non-zero coefficient overall.
            // This condition is met if NOT (both S1 came from all_zeros=true AND S2 came from all_zeros_R=true).
            // Equivalent to: at least one of them came from a path with non-zero coefficients.
            if (!all_zeros_L || !all_zeros_R) {
                found = true; // Mark that a valid solution is found
            }
        }
        return; // End this path of recursion
    }

    // Recursive calls for the next index (index + 1) in the second half:
    // Option 1: Use coefficient 0 for A[index]. The 'all_zeros_R' state remains the same.
    generate_sums_R(index + 1, current_sum, all_zeros_R); 
    if (found) return; // Optimization check after recursive call returns

    // Option 2: Use coefficient +1 for A[index]. Sets 'all_zeros_R' to false for this path.
    generate_sums_R(index + 1, current_sum + A[index], false); 
     if (found) return; // Optimization check

    // Option 3: Use coefficient -1 for A[index]. Sets 'all_zeros_R' to false for this path.
    generate_sums_R(index + 1, current_sum - A[index], false); 
     // No need to check 'found' after the last recursive call in the function body, it's checked at the top.
}


int main() {
    // Use faster I/O operations
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    // Read problem input N and K
    std::cin >> N >> K;
    A.resize(N);
    bool all_input_elements_are_zero = true; // Flag to track if all A[i] are 0
    // Read the N integers into vector A
    for (int i = 0; i < N; ++i) {
        std::cin >> A[i];
        if (A[i] != 0) {
            all_input_elements_are_zero = false; // Set flag to false if any non-zero element found
        }
    }

    // Handle the edge case where all input numbers A[i] are 0.
    if (all_input_elements_are_zero) {
        // If all A_i are 0, any linear combination $\sum c_i A_i$ results in 0.
        // The only value possible is 0.
        if (K == 0) {
            // We can achieve K=0. E.g., take A_1 with coefficient +1. The sum is 1*0=0. The subset {1} is non-empty.
            std::cout << "Yes" << std::endl; 
        } else {
            // If K is non-zero, it's impossible to achieve it from only zeros.
            std::cout << "No" << std::endl; 
        }
        return 0; // Exit program after handling this edge case
    }

    // Calculate the GCD of the absolute values of all elements in A.
    long long common_divisor = calculate_vec_gcd(A);

    // Apply the necessary condition based on GCD.
    // Any achievable number must be divisible by the GCD of the initial numbers.
    // This check is only meaningful if common_divisor is not 0 (i.e., not all A_i are 0).
    if (common_divisor != 0) { 
        // If K is not divisible by the common_divisor, it's impossible to form K.
        if (K % common_divisor != 0) {
            std::cout << "No" << std::endl;
            return 0; // Exit program
        }
    } 
    // Note: If common_divisor is 0, it means all A_i are 0, which was already handled.
    
    // Proceed with the Meet-in-the-Middle approach.
    N1 = N / 2; // Define the split point: first half has N1 elements (0..N1-1)

    // Phase 1: Generate all possible sums for the first half and store results in map_L.
    generate_sums_L(0, 0, true); // Start DFS from index 0, initial sum 0, initially all_zeros is true.

    // Phase 2: Generate sums for the second half and check against map_L if K can be formed.
    // Start DFS for the second half from index N1, initial sum 0, initially all_zeros_R is true.
    generate_sums_R(N1, 0, true); 

    // After exploring possibilities, output the final result based on the 'found' flag.
    if (found) {
        std::cout << "Yes" << std::endl;
    } else {
        std::cout << "No" << std::endl;
    }

    return 0; // Indicate successful execution
}
0