Submission #50849425


Source Code Expand

#include <algorithm>
#include <cstdint>
#include <immintrin.h>
#include <iostream>
#include <random>
#include <string>
#include <tuple>
#include <unordered_set>
#include <vector>

struct BitPoly {
  std::vector<std::uint64_t> bits;

  BitPoly() : bits() {}

  BitPoly(std::string x) {
    unsigned length = x.size();
    bits.resize((length + 63) / 64);
    for (unsigned i = 0; i < length; i++) {
      if (x[i] == '1') {
        bits[i / 64] |= 1ULL << (i % 64);
      }
    }
    reduce();
  }

  void prepare_bit(unsigned i) {
    unsigned vector_pos = i / 64;
    if (vector_pos >= bits.size()) {
      bits.resize(vector_pos + 1);
    }
  }

  void set(unsigned i) {
    prepare_bit(i);
    bits[i / 64] |= 1ULL << (i % 64);
    reduce();
  }

  void flip(unsigned i) {
    prepare_bit(i);
    bits[i / 64] ^= 1ULL << (i % 64);
    reduce();
  }

  bool operator[](unsigned i) const {
    if (i / 64 >= bits.size()) {
      return false;
    }
    return (bits[i / 64] >> (i % 64)) & 1;
  }

  void reduce() {
    while (!bits.empty() && bits.back() == 0) {
      bits.pop_back();
    }
  }

  BitPoly operator+(const BitPoly &other) const {
    BitPoly result = *this;
    if (result.bits.size() < other.bits.size()) {
      result.bits.resize(other.bits.size());
    }
    for (unsigned i = 0; i < other.bits.size(); i++) {
      result.bits[i] ^= other.bits[i];
    }
    result.reduce();
    return result;
  }

  BitPoly operator<<(unsigned shift) const {
    BitPoly result;
    result.bits.resize(bits.size() + (shift + 63) / 64);
    for (unsigned i = 0; i < bits.size(); i++) {
      result.bits[i + shift / 64] |= bits[i] << (shift % 64);
      if (shift % 64 != 0) {
        result.bits[i + shift / 64 + 1] |= bits[i] >> (64 - shift % 64);
      }
    }
    result.reduce();
    return result;
  }

  static std::pair<std::uint64_t, std::uint64_t>
  carryless_mul(std::uint64_t a, std::uint64_t b) {
    __m128i a_ = _mm_cvtsi64_si128(a);
    __m128i b_ = _mm_cvtsi64_si128(b);
    __m128i c = _mm_clmulepi64_si128(a_, b_, 0);
    std::uint64_t low = _mm_extract_epi64(c, 0);
    std::uint64_t high = _mm_extract_epi64(c, 1);
    return {low, high};
  }

  BitPoly operator*(const BitPoly &other) const {
    BitPoly result;
    result.bits.resize(bits.size() + other.bits.size());
    for (unsigned i = 0; i < bits.size(); i++) {
      for (unsigned j = 0; j < other.bits.size(); j++) {
        auto [low, high] = carryless_mul(bits[i], other.bits[j]);
        result.bits[i + j] ^= low;
        result.bits[i + j + 1] ^= high;
      }
    }
    result.reduce();
    return result;
  }

  bool operator==(const BitPoly &other) const {
    if (bits.size() != other.bits.size()) {
      return false;
    }
    for (unsigned i = 0; i < bits.size(); i++) {
      if (bits[i] != other.bits[i]) {
        return false;
      }
    }
    return true;
  }

  unsigned degree() const {
    if (bits.empty()) {
      return 0;
    }
    return 64 * bits.size() - __builtin_clzll(bits.back()) - 1;
  }

  std::pair<BitPoly, BitPoly> divmod(const BitPoly &other) const {
    unsigned self_len = bits.size();
    unsigned other_len = other.bits.size();

    if (self_len < other_len) {
      return {BitPoly(), *this};
    }

    BitPoly quotient;
    quotient.bits.resize(self_len - other_len + 1);
    BitPoly remainder = *this;
    for (unsigned i = self_len - 1; i + 1 >= other_len; i--) {
      unsigned shift = i + 1 - other_len;
      __uint128_t a = 0;
      if (i + 1 < self_len) {
        a = remainder.bits[i + 1];
        a <<= 64;
      }
      a |= remainder.bits[i];
      __uint128_t b = other.bits[other_len - 1];
      b <<= 64;
      if (other_len >= 2) {
        b |= other.bits[other_len - 2];
      }

      std::uint64_t q = 0;
      for (unsigned j = 1; j <= 64; j++) {
        __uint128_t shift_b = b >> j;
        if ((a ^ shift_b) < a) {
          a ^= shift_b;
          q |= 1ULL << (64 - j);
        }
      }

      for (unsigned j = 0; j < other_len; j++) {
        auto [low, high] = carryless_mul(q, other.bits[j]);

        if (j + shift < self_len - 1) {
          remainder.bits[j + shift + 1] ^= high;
        }
        remainder.bits[j + shift] ^= low;
      }
      quotient.bits[shift] = q;
    }

    quotient.reduce();
    remainder.reduce();

    return {quotient, remainder};
  }

  BitPoly operator/(const BitPoly &other) const { return divmod(other).first; }

  BitPoly operator%(const BitPoly &other) const { return divmod(other).second; }

  std::tuple<BitPoly, BitPoly, BitPoly> extgcd(const BitPoly &other) const {
    BitPoly a = *this, b = other;
    BitPoly sa("1"), ta, sb, tb("1");

    while (!b.bits.empty()) {
      auto [q, r] = a.divmod(b);
      a = b;
      b = r;
      BitPoly tmp = sa;
      sa = sb;
      sb = tmp + sa * q;
      tmp = ta;
      ta = tb;
      tb = tmp + ta * q;
    }
    return {sa, ta, a};
  }

  std::uint64_t hash() const {
    static std::random_device seed_gen;
    static std::uint64_t base = (seed_gen() & ((1ULL << 63) - 1)) << 1;
    std::uint64_t result = 0;
    for (std::uint64_t x : bits) {
      std::uint64_t x1 = x >> 32, x2 = x & ((1ULL << 32) - 1);
      {
        auto [low, high] = carryless_mul(result ^ x1, base);
        result = low >> 1 ^ high ^ high << 1;
      }
      {
        auto [low, high] = carryless_mul(result ^ x2, base);
        result = low >> 1 ^ high ^ high << 1;
      }
    }
    return result;
  }

  BitPoly mod_pow(unsigned k, const BitPoly &mod) const {
    BitPoly result("1");
    BitPoly base = *this;
    while (k > 0) {
      if (k & 1) {
        result = result * base % mod;
      }
      base = base * base % mod;
      k >>= 1;
    }
    return result;
  }
};

void multiply_by_x(BitPoly &f, BitPoly &mod) {
  f = f << 1;
  if (f[mod.degree()]) {
    f = f + mod;
  }
}

int main() {
  unsigned n;
  std::string s, t;
  std::cin >> n >> s >> t;

  BitPoly f_s(s), f_t(t);

  unsigned p;
  std::cin >> p;
  BitPoly f_a;
  for (unsigned i = 0; i < p; i++) {
    unsigned a;
    std::cin >> a;
    f_a.set(a - 1);
  }
  f_a.flip(0);
  f_a.flip(n);

  unsigned q;
  std::cin >> q;
  BitPoly f_b;
  for (unsigned i = 0; i < q; i++) {
    unsigned b;
    std::cin >> b;
    f_b.set(b - 1);
  }

  auto [f_p, f_q, f_g] = f_a.extgcd(f_b);

  auto output = [&](const BitPoly &ans, unsigned length) {
    std::string ans_str(length, '0');
    for (unsigned i = 0; i <= ans.degree(); i++) {
      if (ans[i]) {
        ans_str[length - 1 - i] = '1';
      }
    }
    std::cout << length << std::endl << ans_str << std::endl;
  };

  unsigned f_g_degree = f_g.degree();
  BitPoly f_s_mod_g = f_s % f_g, f_t_mod_g = f_t % f_g;
  BitPoly f_s_q_mod_a = f_s * f_q % f_a, f_t_q_mod_a = f_t * f_q % f_a;

  const unsigned STEP_SIZE = 1000;

  for (unsigned i = 1; i <= std::max(n, STEP_SIZE); i++) {
    multiply_by_x(f_s_mod_g, f_g);
    multiply_by_x(f_s_q_mod_a, f_a);
    BitPoly f_st_q_mod_a = f_s_q_mod_a + f_t_q_mod_a;
    if (f_s_mod_g == f_t_mod_g && f_st_q_mod_a.degree() < i + f_g_degree) {
      output(f_st_q_mod_a / f_g, i);
      return 0;
    }
  }

  std::unordered_set<std::uint64_t> baby_step;
  f_t_mod_g = f_t % f_g;
  BitPoly f_x_step_mod_g("1");
  for (unsigned i = 0; i < STEP_SIZE; i++) {
    baby_step.insert(f_t_mod_g.hash());
    multiply_by_x(f_t_mod_g, f_g);
    multiply_by_x(f_x_step_mod_g, f_g);
  }
  f_s_mod_g = f_s % f_g;
  f_t_mod_g = f_t % f_g;
  unsigned failure_cnt = 0;
  for (unsigned i = 0; i <= (unsigned)1e6; i += STEP_SIZE) {
    BitPoly next_f_s_mod_g = f_s_mod_g * f_x_step_mod_g % f_g;

    if (baby_step.contains(next_f_s_mod_g.hash())) {
      for (unsigned j = 1; j <= STEP_SIZE; j++) {
        unsigned k = i + j;
        multiply_by_x(f_s_mod_g, f_g);
        if (n < k && k <= (unsigned)1e6 && f_s_mod_g == f_t_mod_g) {
          output((f_s * BitPoly("01").mod_pow(k, f_a) + f_t) * f_q % f_a / f_g,
                 k);
          return 0;
        }
      }
      if (n < i && ++failure_cnt == 2) {
        break;
      }
    }
    f_s_mod_g = next_f_s_mod_g;
  }

  std::cout << -1 << '\n';
}

Submission Info

Submission Time
Task F - Flip or Not
User Mitarushi
Language C++ 20 (gcc 12.2)
Score 100
Code Size 8406 Byte
Status AC
Exec Time 15 ms
Memory 4456 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 100 / 100
Status
AC × 2
AC × 58
Set Name Test Cases
Sample 00_sample_00, 00_sample_01
All 00_sample_00, 00_sample_01, 01_min_00, 02_small_00, 02_small_01, 02_small_02, 02_small_03, 02_small_04, 03_small_00, 03_small_01, 03_small_02, 03_small_03, 03_small_04, 04_small_00, 04_small_01, 04_small_02, 04_small_03, 04_small_04, 04_small_05, 04_small_06, 04_small_07, 04_small_08, 04_small_09, 05_large_00, 05_large_01, 05_large_02, 05_large_03, 05_large_04, 06_large_00, 06_large_01, 06_large_02, 06_large_03, 06_large_04, 07_large_00, 07_large_01, 07_large_02, 07_large_03, 07_large_04, 07_large_05, 07_large_06, 07_large_07, 07_large_08, 07_large_09, 08_max_00, 08_max_01, 08_max_02, 08_max_03, 08_max_04, 09_max_00, 09_max_01, 09_max_02, 09_max_03, 09_max_04, 09_max_05, 09_max_06, 09_max_07, 09_max_08, 09_max_09
Case Name Status Exec Time Memory
00_sample_00 AC 1 ms 3472 KiB
00_sample_01 AC 1 ms 3480 KiB
01_min_00 AC 1 ms 3584 KiB
02_small_00 AC 1 ms 3572 KiB
02_small_01 AC 1 ms 3544 KiB
02_small_02 AC 1 ms 3504 KiB
02_small_03 AC 1 ms 3544 KiB
02_small_04 AC 1 ms 3448 KiB
03_small_00 AC 1 ms 3504 KiB
03_small_01 AC 1 ms 3512 KiB
03_small_02 AC 1 ms 3480 KiB
03_small_03 AC 1 ms 3484 KiB
03_small_04 AC 1 ms 3572 KiB
04_small_00 AC 1 ms 3544 KiB
04_small_01 AC 1 ms 3480 KiB
04_small_02 AC 1 ms 3668 KiB
04_small_03 AC 1 ms 3544 KiB
04_small_04 AC 1 ms 3576 KiB
04_small_05 AC 1 ms 3536 KiB
04_small_06 AC 1 ms 3484 KiB
04_small_07 AC 1 ms 3544 KiB
04_small_08 AC 1 ms 3544 KiB
04_small_09 AC 1 ms 3668 KiB
05_large_00 AC 2 ms 3520 KiB
05_large_01 AC 4 ms 3680 KiB
05_large_02 AC 4 ms 3540 KiB
05_large_03 AC 2 ms 3572 KiB
05_large_04 AC 5 ms 3664 KiB
06_large_00 AC 7 ms 3680 KiB
06_large_01 AC 10 ms 3576 KiB
06_large_02 AC 11 ms 3568 KiB
06_large_03 AC 9 ms 3660 KiB
06_large_04 AC 3 ms 3712 KiB
07_large_00 AC 4 ms 3632 KiB
07_large_01 AC 4 ms 3720 KiB
07_large_02 AC 6 ms 3724 KiB
07_large_03 AC 3 ms 3968 KiB
07_large_04 AC 9 ms 3912 KiB
07_large_05 AC 8 ms 3696 KiB
07_large_06 AC 7 ms 3704 KiB
07_large_07 AC 7 ms 3676 KiB
07_large_08 AC 2 ms 3648 KiB
07_large_09 AC 13 ms 3912 KiB
08_max_00 AC 5 ms 3680 KiB
08_max_01 AC 5 ms 3684 KiB
08_max_02 AC 5 ms 3752 KiB
08_max_03 AC 5 ms 3724 KiB
08_max_04 AC 4 ms 3684 KiB
09_max_00 AC 12 ms 3632 KiB
09_max_01 AC 14 ms 4184 KiB
09_max_02 AC 11 ms 4456 KiB
09_max_03 AC 7 ms 4360 KiB
09_max_04 AC 12 ms 4440 KiB
09_max_05 AC 13 ms 3536 KiB
09_max_06 AC 12 ms 3624 KiB
09_max_07 AC 15 ms 4184 KiB
09_max_08 AC 15 ms 4240 KiB
09_max_09 AC 14 ms 4184 KiB