Skip to content

Commit

Permalink
feat: Gosper's hack
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiphereth-A committed Mar 18, 2024
1 parent b809e4b commit a659905
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 0 deletions.
3 changes: 3 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ notebook:
- enumerate: enumerate
code_ext: hpp
test_ext: cpp
- gosper: 枚举 n 位二进制数中恰有 k 个 1 的数
code_ext: hpp
test_ext: cpp
io:
- ios128: 128 位整数的 IO
code_ext: hpp
Expand Down
34 changes: 34 additions & 0 deletions src/code/enum/gosper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef TIFALIBS_ENUM_GOSPER
#define TIFALIBS_ENUM_GOSPER

#include "../bit/lowbit.hpp"

namespace tifa_libs {

template <u32 ID = 0>
class Gosper {
static inline u32 n_, k_;
u64 now_;

public:
static constexpr void set(u32 n, u32 k) {
assert(k <= n && n < 64);
n_ = n;
k_ = k;
}
static Gosper begin() { return (1_u64 << k_) - 1; }
static Gosper end() { return 1_u64 << n_; }

constexpr Gosper(u64 now = *begin()) : now_(now) { assert(now == *end() || std::popcount(now) == k_); }

constexpr u64 operator*() const { return now_; }
constexpr bool operator!=(Gosper const &x) const { return now_ != x.now_; }
constexpr void operator++() {
u64 c = bit::lowbit(now_), r = now_ + c;
now_ = ((r ^ now_) / 4 / c) | r;
}
};

} // namespace tifa_libs

#endif
4 changes: 4 additions & 0 deletions src/doc_md/enum/gosper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: gosper
documentation_of: //src/code/enum/gosper.hpp
---
Empty file added src/doc_tex/enum/gosper.tex
Empty file.
49 changes: 49 additions & 0 deletions src/test_cpverifier/unit-test/enum/gosper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#define UNITTEST
#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"

#include "../../../code/enum/gosper.hpp"

#include "../../../code/comb/binom.hpp"
#include "../../../code/math/mint.hpp"
#include "../../../code/math/mintdata_s30.hpp"
#include "../base.hpp"

using mint = tifa_libs::math::mint<tifa_libs::math::mintdata_s30<998244353>>;

template <u32 ID>
void test(u32 n, u32 kmax) {
using Gosper = tifa_libs::Gosper<ID>;
auto binom = tifa_libs::math::Binom<mint>(n);
for (u32 k = 0; k <= kmax; ++k) {
Gosper::set(n, k);
Gosper gs;
u32 cnt = 0, cnt_correct = binom.mCn(n, k).val();
for (auto i : gs) {
++cnt;
check((u32)std::popcount(i), k, check_param(n), check_param(k), check_param(std::bitset<64>(i).to_string()));
}
check(cnt, cnt_correct, check_param(n), check_param(k));
}
}

int main() {
auto tcase = tifa_libs::unittest::pre_test();

switch (tcase) {
case tifa_libs::unittest::ts_example_00: test<1>(1, 1); break;
case tifa_libs::unittest::ts_example_01: test<1>(2, 2); break;
case tifa_libs::unittest::ts_random_00: test<1>(3, 3); break;
case tifa_libs::unittest::ts_random_01: test<1>(4, 4); break;
case tifa_libs::unittest::ts_random_02: test<1>(5, 5); break;
case tifa_libs::unittest::ts_random_03: test<1>(6, 6); break;
case tifa_libs::unittest::ts_random_04: test<2>(10, 10); break;
case tifa_libs::unittest::ts_random_05: test<2>(20, 20); break;
case tifa_libs::unittest::ts_random_06: test<2>(30, 10); break;
case tifa_libs::unittest::ts_random_07: test<2>(40, 8); break;
case tifa_libs::unittest::ts_random_08: test<2>(50, 7); break;
case tifa_libs::unittest::ts_random_09: test<2>(60, 6); break;
default: break;
}

tifa_libs::unittest::post_test();
}
Empty file.

0 comments on commit a659905

Please sign in to comment.