Halfway search (meeting in the middle) + violent enumeration: PIPI's alchemy

Halfway search (meeting in the middle) + violent enumeration: PIPI's alchemy

question:

insert image description here
insert image description here

Ideas:

  First, we need to transform the problem. According to the meaning of the question, we can successfully alchemy several materials, as long as the sum of the characters of these material strings is an even number, and the material strings are all composed of lowercase letters, and the lowercase letters az can correspond to numbers 0-25. Therefore, we can consider the following operations: We record whether the number of occurrences of characters in each string is even or odd, and save it in a two-dimensional array alphabet, indicating that the number of occurrences of the letter j of the i-th string is even alphabet[i][j]=0, alphabet[i][j]=1indicating the i-th The string has an odd number of occurrences of the letter j. Then we can convert the information of whether the number of occurrences of the 26 letters of each material string is even or odd into a 26-bit binary number. If a certain bit is 1, it means that the number of occurrences of the corresponding letter at this position is odd, and vice versa is an even number. Then n strings become n numbers, so the problem becomes: for n numbers, you can choose any number (but the number must be greater than 0) from them, XOR them all, and the other If the value is 0, it is a legal scheme (because if the number of occurrences of letters in the combined string is even, the number of occurrences of the letter in the combined original string is either odd or even, which means It just corresponds to the situation of 1 1 and 0 0 in the corresponding binary digits, and the same XOR is 0, which happens to correspond to an even number of occurrences of letters after the combination, and then if the XOR result is a value of 0, then all binary bits are is 0, corresponding to an even number of occurrences of all characters, which is the condition in the question).
  After the conversion, it is time to count the number of solutions. Any string can be combined in the question. For each string, obviously, there are two choices: choose or not, so it is easy to think of O(2^n) violent enumeration method, from 000...001 to 111 …111, and then XOR the corresponding selected string through bit operation and shift. However, the size of n in this question is 35, and the time complexity is too much to pass. At this time, we need to use the half search method to optimize the time complexity.
  The halfway search is also called the halfway meet method. Simply put, it is to process the first half, store the result, process the second half, and then match the result stored in the first half. That is, when enumerating the second half, the results generated by the first half are used to avoid double calculation.
  For this question, it is to enumerate half first, enumerating from 1 (corresponding to 000...001) to2 ^ (n / 2 + 1) - 1(corresponding to 000...111...111), if the XOR result is 0, then the result ans++ means that a solution has been found, no matter what the XOR result is, the number of calculated XOR results will be stored in a hash table. Then we enumerate the other half, from 2 ^ (n / 2 + 1)(corresponding to 000...100...000) enumeration to all 1s in the second half (that is, corresponding to 111...111000...000), note that when we enumerate the second half, the step size is, that is, we 2 ^ (n/2 + 1)enumerate The second half means enumerating the strings in the second half. At this time, we don’t consider the strings in the first half at all, that is, the binary bits in the first half of the enumeration are all 0. If the XOR result is 0, the result ans++ means that a solution has been found. No matter what the XOR result is, the hash table will be queried. If the currently calculated XOR value is saved in the hash table, it means that in the first half of the enumeration If it is exactly the same as the current character parity distribution, then we need to use ans to add the number of schemes stored in the hash table, because the previously saved schemes can be combined with the current scheme to meet the requirements of the topic. (Because if the odd-even distribution of characters in two combined strings is exactly the same, then they are combined again, and all characters must appear an even number of times).
  In this way, through the half search, the time complexity is optimized from O(2 ^ n) to O(2 ^ (n/2)).

code:

import java.util.*;

public class Main {
    
    
    static int[][] alphabet = new int[37][27];
    static long[] hash = new long[37];
    static long[] twoMul = new long[37];
    static HashMap<Long, Long> num = new HashMap<>();
    public static void main(String[] args) {
    
    
        int n, i, j, count;
        long loop, temp, k, ans = 0, hVal;
        twoMul[0] = 1;
        for (i = 1; i < 37; i++) {
    
    
            twoMul[i] = twoMul[i - 1] * 2;
        }
        StringBuilder stringBuilder = new StringBuilder();
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        for (i = 0; i < n; i++) {
    
    
            stringBuilder.delete(0, stringBuilder.length());
            stringBuilder.append(scanner.next());
            for (j = 0; j < stringBuilder.length(); j++) {
    
    
                if (alphabet[i][stringBuilder.charAt(j)-'a'] == 1) {
    
    
                    alphabet[i][stringBuilder.charAt(j)-'a'] = 0;
                } else {
    
    
                    alphabet[i][stringBuilder.charAt(j)-'a'] = 1;
                }
            }
        }
        for (i = 0; i < n; i++) {
    
    
            for (j = 0; j < 26; j++) {
    
    
                hash[i] += alphabet[i][j] * twoMul[j];
            }
        }
        for (loop = 1; loop <= twoMul[n / 2 + 1] - 1; loop++) {
    
    
            temp = loop;
            count = 0;
            k = 0;
            while (temp != 0) {
    
    
                if ((temp & 1) != 0) {
    
    
                    k = hash[count] ^ k;
                }
                temp >>= 1;
                count++;
            }
            if (k == 0 && count != 0) {
    
    
                ans++;
            }
            if (num.get(k) != null) {
    
    
                hVal = num.get(k);
                num.put(k, hVal + 1);
            } else {
    
    
                num.put(k, 1L);
            }
        }
        for (; loop <= twoMul[n] - 1; loop += twoMul[n / 2 + 1]) {
    
    
            temp = loop;
            count = n / 2 + 1;
            k = 0;
            while (temp >= twoMul[n / 2 + 1]) {
    
    
                if ((temp & twoMul[n / 2 + 1]) != 0) {
    
    
                    k = hash[count] ^ k;
                }
                temp >>= 1;
                count++;
            }
            if (k == 0 && count != n / 2 + 1) {
    
    
                ans++;
            }
            if (num.get(k) != null) {
    
    
                hVal = num.get(k);
                ans += hVal;
            }
        }
        System.out.println(ans);
    }


}

Guess you like

Origin blog.csdn.net/qq_44709990/article/details/123456434