好用的模板
网络流合集。包含 ISAP 最大流,Dinic + Dijkstra 费用流
//template <typename T>
//using heap = std::priority_queue<T, std::vector<T>, std::greater<T>>;
class network_flow_t { // 记得边是从 0 起的!!!
std::vector<std::vector<int>> head; // 存图的顶点连哪些边(存索引)
std::vector<std::pair<int, int>> edges{}; // 所有的边
std::vector<int> depth, current, costs, distance, h; // current 用于当前弧优化, h 是势
std::vector<bool> visited; // 用于 dinic 算法的 dfs
std::unordered_map<int, int> gap{}; // isap 的 gap 优化
static const int INF = INT32_MAX;
public:
// 只给定顶点数,边数实时动态分配(数据过大可能会引发 std::bac_alloc)
network_flow_t(size_t len) : head(len), depth(len) {}
// 给定顶点数和边数(会自动计算反向边),适用边数确定的情况
network_flow_t(size_t len, size_t cnt, bool use_cost = false)
: head(len), depth(len) {
edges.reserve(cnt << 1); // 考虑反向边,要乘 2
if (use_cost) // 启用费用边模式时还要分配它的空间
costs.reserve(cnt << 1);
}
// FROM u, TO v, Flow f
void connect(int u, int v, int f) {
head[u].emplace_back(edges.size());
edges.emplace_back(v, f);
head[v].emplace_back(edges.size()); // 建立反向边,这样建边,可以直接通过异或求得反向边的编号
edges.emplace_back(u, 0);
}
// From u, To v, Flow f, Cost c
void connect(int u, int v, int f, int c) {
connect(u, v, f);
costs.emplace_back(c);
costs.emplace_back(-c); // 反向边的费用是负数
}
// 以下为最大流算法 isap 实现
private:
void _isap_bfs(int end) { // 从后往前分层
std::fill(depth.begin(), depth.end(), -1);
gap.clear();
depth[end] = 0;
gap[end] = 1;
std::queue<int> queue;
queue.emplace(end);
do {
auto u = queue.front();
queue.pop();
for (const auto &idx : head[u]) {
const auto &[v, f] = edges[idx];
if (depth[v] != -1)
continue;
depth[v] = depth[u] + 1;
gap[depth[v]]++;
queue.emplace(v);
}
} while (not queue.empty());
}
int _isap_dfs(int u, int flow, const int &start, const int &end) {
if (u == end)
return flow;
int used = 0;
for (int &cur = current[u]; cur < head[u].size(); ++cur) {
const auto &idx = head[u][cur];
auto &&[v, f] = edges[idx];
if (f < 1 or depth[u] != depth[v] + 1) // depth 是反向的,记住
continue;
auto spend = _isap_dfs(v, std::min(f, flow - used), start, end);
if (spend == 0)
continue;
auto &&[_, rf] = edges[idx ^ 1]; // 求出这条边的反向边
f -= spend;
rf += spend;
used += spend;
if (used == flow)
return flow;
}
--gap[depth[u]];
if (gap[depth[u]] == 0)
depth[start] = head.size() + 1;
++depth[u];
++gap[depth[u]];
return used;
}
public:
long maximum_flow(int start, int end) {
long result = 0;
_isap_bfs(end);
current.resize(head.size());
while (depth[start] < head.size()) {
std::fill(current.begin(), current.end(), 0);
result += _isap_dfs(start, INF, start, end);
}
return result;
}
// 以下为最小费用最大流算法 dinic + dijkstra 实现
private:
bool _dijkstra(int start, int end) {
std::fill(distance.begin(), distance.end(), INF);
std::heap<std::pair<long, int>> heap;
distance[start] = 0;
heap.emplace(distance[start], start);
do {
auto [d, u] = heap.top();
heap.pop();
if (distance[u] < d)
continue;
for (const auto &idx : head[u]) {
const auto &[v, f] = edges[idx];
const auto &c = costs[idx];
const auto new_distance = distance[u] + c + h[u] - h[v];
if (f == 0 or distance[v] <= new_distance)
continue;
distance[v] = new_distance;
heap.emplace(distance[v], v);
}
} while (not heap.empty());
return distance[end] != INF;
}
int _dinic_dfs(int u, int flow, const int &start, const int &end) {
if (u == end)
return flow;
int used = 0;
visited[u] = true;
for (int &cur = current[u]; cur < head[u].size(); ++cur) {
const auto &idx = head[u][cur];
auto &&[v, f] = edges[idx];
const auto &c = costs[idx];
const auto new_distance = distance[u] + c + h[u] - h[v];
if (visited[v] or f == 0 or distance[v] != new_distance)
continue;
auto spend = _dinic_dfs(v, std::min(flow - used, f), start, end);
auto &&[_, rf] = edges[idx ^ 1];
f -= spend;
rf += spend;
used += spend;
if (flow == used)
break;
}
visited[u] = false;
return used;
}
public:
std::pair<long, long> minimum_cost_maximum_flow(int start, int end) {
long flow = 0, cost = 0;
h.assign(head.size(), 0);
distance.resize(head.size());
visited.assign(head.size(), false);
current.resize(head.size());
while (_dijkstra(start, end)) {
std::fill(current.begin(), current.end(), 0);
auto result = _dinic_dfs(start, INF, start, end);
for (int i = 0; i < head.size(); ++i)
h[i] += distance[i] == INF ? 0 : distance[i];
flow += result;
cost += result * h[end];
}
return {cost, flow};
}
public:
void clear_edges() {
head.assign(head.size(), std::vector<int>());
edges.clear();
costs.clear();
gap.clear();
}
}; // 记得边是从 0 起的!!!欧拉筛
class prime_table {
std::vector<long> primes;
std::vector<bool> isPrimes;
public:
prime_table(const long &n) : isPrimes(n + 1, true) {
for (long i = 2; i <= n; ++i) {
if (isPrimes[i])
primes.emplace_back(i);
for (auto &&prime : primes) {
if (i * prime > n)
break;
isPrimes[i * prime] = false;
if (i % prime == 0)
break;
}
}
}
std::vector<long> get_primes() {
return primes;
}
bool is_primes(const size_t &index) {
return isPrimes[index];
}
long operator[](const size_t &index) {
return primes[index];
}
};
珂树
template<typename T>
class ChthollyTree {
set<tuple<size_t, size_t, T> > tree;
using iterator = set<tuple<size_t, size_t, T> >::iterator;
iterator split(const size_t &posation) {
auto it = tree.lower_bound({posation, 0, 0});
if(it != tree.end() and get<0>(*it) == posation)
return it;
--it;
auto [left, right, data] = *it;
tree.erase(it);
if (left < posation)
tree.emplace(left, posation - 1, data);
if (right >= posation)
return tree.emplace(posation, right, data).first;
return tree.end();
}
public:
// 左闭右开
void assign(const size_t &left, const size_t &right, const T & data) {
auto end = split(right), begin = split(left);
tree.erase(begin, end);
tree.emplace(left, right - 1, data);
}
void add_node(const tuple<size_t, size_t, T>& node) {
tree.emplace(node);
}
// 左闭右开
void add_range(const size_t &left, const size_t &right, const T & data) {
auto end = split(right), begin = split(left);
for(auto it = begin; it != end; ++it)
get<2>(*it) += data;
}
// 左闭右开
T range_sum(const size_t &left, const size_t &right) {
auto end = split(right), begin = split(left);
T result = 0;
for(auto it = begin; it != end; ++it)
result += get<2>(*it);
return result;
}
T range_sum(const size_t &left, const size_t &right, const T &mod) {
auto end = split(right), begin = split(left);
T result = 0;
for(auto it = begin; it != end; ++it)
result = (result + get<2>(*it)) % mod;
return result;
}
// 左闭右开
T kth_element(const size_t &left, const size_t &right, const size_t k) {
auto end = split(right), begin = split(left);
list<pair<T, size_t>> nodes;
for(auto it = begin; it != end; ++it) {
auto &&[left, right, data] = *it;
nodes.emplace_back(data, right - left + 1);
}
for(auto &&[data, span] : nodes) {
k -= span;
if (k <= 0)
return data;
}
return -1;
}
T ask(const size_t &posation) {
return get<2>(prev(tree.upper_bound({posation, -1, T{}})));
}
T ask_range(const size_t &left, const size_t &right) {
auto end = split(right), begin = split(left);
T result{};
for(auto it = begin; it != end; ++it)
result += get<2>(*it);
return result;
}
ChthollyTree(const vector<T> &array) {
const auto len = array.size();
for (std::int64_t l = 0, r = 0; r < len; l = r) {
while (r < len and array[l] == array[r])
r++;
add_node({l + 1, r, array[l]});
}
}
void show() {
for(auto &&[left, right, data] : tree) {
for(auto i = left; i <= right; ++i)
cout << data << endl;
}
}
};跳表
#include <iostream>
#include <limits>
#include <random>
#include <stdexcept>
#include <string>
#include <vector>
template <typename T, size_t kMaxLevel = 16> class Skiplist {
struct Node {
T Key;
std::vector<size_t> SkipSpans;
std::vector<Node *> Nexts;
Node(const T &key, const size_t &size)
: Key(key), SkipSpans(size + 1, 0), Nexts(size + 1, nullptr) {}
};
std::bernoulli_distribution rand_;
std::minstd_rand seed_{std::random_device{}()};
size_t count_ = 0;
Node *head_ = new Node(std::numeric_limits<T>::min(), kMaxLevel);
size_t random_level() {
size_t level = 1;
while (level < kMaxLevel and rand_(seed_))
level++;
return level;
}
std::pair<std::vector<Node *>, std::vector<size_t>>
search_updates(const T &item) {
std::vector<Node *> updates(kMaxLevel + 1);
auto current = head_;
std::vector<size_t> totalSpans(kMaxLevel + 2, 0);
for (auto level = kMaxLevel; level != -1; --level) {
totalSpans[level] = totalSpans[level + 1];
while (current->Nexts[level] and
current->Nexts[level]->Key < item) {
totalSpans[level] += current->SkipSpans[level];
current = current->Nexts[level];
}
updates[level] = current;
}
return {updates, totalSpans};
}
Node *lower_bound(const T &item) {
auto current = head_;
for (auto level = kMaxLevel; level != -1; --level)
while (current->Nexts[level] and current->Nexts[level]->Key < item)
current = current->Nexts[level];
return current;
}
Node *upper_bound(const T &item) {
auto current = head_;
for (auto level = kMaxLevel; level != -1; --level)
while (current->Nexts[level] and current->Nexts[level]->Key <= item)
current = current->Nexts[level];
return current;
}
public:
bool empty() { return count_ == 0; }
size_t size() { return count_; }
void add(const T &item) {
auto [updates, totalSpans] = search_updates(item);
auto level = random_level();
auto newNode = new Node(item, level);
if (newNode == nullptr)
throw std::bad_alloc();
const auto totalSpan = totalSpans.front() + 1;
for (size_t currentLevel = 0; currentLevel <= level; ++currentLevel) {
newNode->Nexts[currentLevel] =
updates[currentLevel]->Nexts[currentLevel];
updates[currentLevel]->Nexts[currentLevel] = newNode;
auto diff = totalSpan - totalSpans[currentLevel];
if (newNode->Nexts[currentLevel])
newNode->SkipSpans[currentLevel] =
updates[currentLevel]->SkipSpans[currentLevel] - diff + 1;
updates[currentLevel]->SkipSpans[currentLevel] = diff;
}
// 记得处理在高层前插入低层的情况的 skipSpan
for (auto currentLevel = level + 1; currentLevel <= kMaxLevel;
++currentLevel)
if (updates[currentLevel]->Nexts[currentLevel])
updates[currentLevel]->SkipSpans[currentLevel]++;
count_++;
}
bool erase(const T &item) {
if (empty())
return false;
auto updates = search_updates(item).first;
auto node = updates.front()->Nexts.front();
if (node == nullptr or node->Key != item)
return false;
for (size_t currentLevel = 0; currentLevel < node->Nexts.size();
++currentLevel) {
if (updates[currentLevel]->Nexts[currentLevel] != node)
continue;
updates[currentLevel]->Nexts[currentLevel] =
node->Nexts[currentLevel];
if (updates[currentLevel]->Nexts[currentLevel])
updates[currentLevel]->SkipSpans[currentLevel] +=
node->SkipSpans[currentLevel] - 1;
else
updates[currentLevel]->SkipSpans[currentLevel] = 0;
}
// 记得处理在高层前删除低层的情况的 skipSpan
for (auto currentLevel = node->Nexts.size(); currentLevel <= kMaxLevel;
++currentLevel)
if (updates[currentLevel]->Nexts[currentLevel])
updates[currentLevel]->SkipSpans[currentLevel]--;
delete node;
count_--;
return true;
}
bool search(const T &item) {
auto updates = search_updates(item).first;
auto node = updates.front()->Nexts.front();
return node and node->Key == item;
}
size_t rank_of(const T &item) {
return search_updates(item).second.front() + 1;
}
T nth_element(const size_t &rank) {
if (rank > count_)
throw std::out_of_range("rank can't not greater than list size");
size_t currentRank = 0;
auto current = head_;
for (auto currentLevel = kMaxLevel; currentLevel != -1; --currentLevel)
while (current->Nexts[currentLevel] and
current->SkipSpans[currentLevel] + currentRank <= rank) {
currentRank += current->SkipSpans[currentLevel];
current = current->Nexts[currentLevel];
}
return current->Key;
}
T lower_to(const T &item) { return lower_bound(item)->Key; }
T upper_to(const T &item) { return upper_bound(item)->Nexts[0]->Key; }
class iterator {
Node *current_;
public:
iterator(Node *start) : current_(start) {}
T &operator*() { return current_->Key; }
iterator &operator++() {
current_ = current_->Nexts[0];
return *this;
}
bool operator!=(const iterator &other) const {
return current_ != other.current_;
}
};
iterator begin() const { return iterator(head_->Nexts[0]); }
iterator end() const { return iterator(nullptr); }
void makeView() {
std::endl(std::cout);
for (auto current = head_; current != nullptr;
current = current->Nexts[0]) {
for (size_t i = 0; i < current->Nexts.size(); ++i)
std::cout << current->Key << '['
<< (current->Nexts[i]
? std::to_string(current->Nexts[i]->Key)
: "nullptr")
<< "](" << current->SkipSpans[i] << ") ";
std::endl(std::cout);
}
std::endl(std::cout);
}
Skiplist(const double &p = 0.5) : rand_(p) {}
~Skiplist() {
auto current = head_;
while (current) {
auto next = current->Nexts[0];
delete current;
current = next;
}
}
};组合数
class combination {
vector<int64_t> inv_factorial_, factorial_;
int64_t mod_;
static int64_t quick_power(int64_t base, int64_t power, int64_t mod) {
auto result = 1;
while (power) {
if (power & 1)
result = (result * base) % mod;
base = (base * base) % mod;
power >>= 1;
}
return result;
}
public:
combination(const int64_t &n, const int64_t &mod)
: inv_factorial_(n + 1), factorial_(n + 1), mod_(mod) {
factorial_[0] = 1;
for (auto &&i = 1ll; i <= n; ++i)
factorial_[i] = factorial_[i - 1] * i % mod_;
inv_factorial_[n] = quick_power(factorial_[n], mod_ - 2, mod_);
for(auto i = n - 1; i >= 0; --i)
inv_factorial_[i] = inv_factorial_[i + 1] * (i + 1) % mod_;
}
int64_t C(const int64_t &down, const int64_t &up) const {
if(up > down or up < 0)
return 0;
return factorial_[down] * inv_factorial_[up] % mod_ * inv_factorial_[down - up] % mod_;
}
};
auto loader = combination(2e6, 998244353);究极压位高精度整数
#include <bits/stdc++.h>
#pragma region heads
#ifndef _MSC_VER
#if __cplusplus >= 202000
template <typename... Args>
void print(const std::string_view fmt, const Args &...args) {
std::cout << std::vformat(fmt, std::make_format_args(args...));
}
template <typename... Args>
void println(const std::string_view fmt, const Args &...args) {
std::cout << std::vformat(fmt, std::make_format_args(args...));
std::cout.put('\n');
}
void print(const std::string_view s) { std::cout << s; }
void println(const std::string_view s) { std::cout << s << '\n'; }
#endif
#endif
void println() { std::cout.put('\n'); }
#pragma region Bigint
class Bigint {
using int128_t = __int128;
std::vector<uint64_t> _data;
constexpr static uint64_t _base = 10000000000000000000ull; // 1e19
constexpr static uint8_t _len = 19;
bool _isNegative;
Bigint(const std::vector<uint64_t> &data, const bool isNegative)
: _data(data), _isNegative(isNegative) {
}
// 快速幂
static Bigint pow(Bigint &base, Bigint &power) {
Bigint result = 1;
while (power) {
if (power.is_odd())
result *= base;
base *= base;
power /= 2;
}
return result;
}
static void lhsToValue(const Bigint &value, Bigint &other) {
std::string s = other.to_string();
for (int128_t i = value.to_string().size() - s.size(); i--;)
s += '0';
other = Bigint(s);
}
static void rhs(Bigint &other) {
for (int128_t i = other._data.size() - 1, mod = 0; i >= 0; --i) {
const auto tmp = mod * _base + other._data[i];
mod = tmp % 10;
other._data[i] = tmp / 10;
if (other._data[i] == 0 and i and i + 1 == other._data.size())
other._data.pop_back();
}
}
Bigint div_mod(const Bigint &other, Bigint &modulo) const {
if (other == 0)
throw std::invalid_argument("Division by zero");
if (*this == 0) {
modulo = 0;
return 0;
}
const bool resultNegative = _isNegative != other._isNegative;
const bool moduloNegative = _isNegative;
Bigint current(_data, false), dividend(other._data, false);
if (current < dividend) {
modulo = *this;
return 0;
}
const auto raw_dividend = dividend;
// 对齐位数
lhsToValue(current, dividend);
std::string s;
for (size_t total = 0; current >= raw_dividend;) {
while (current >= dividend) {
current -= dividend;
total++;
}
if (total or not s.empty()) {
s += std::to_string(total);
total = 0;
}
rhs(dividend);
}
modulo = Bigint(current._data, moduloNegative);
if (resultNegative)
s = "-" + s;
while (dividend >= raw_dividend) {
rhs(dividend);
s += '0';
}
return Bigint(s);
}
public:
// 隐式类型转换
explicit operator bool() const { return *this != Bigint(0); }
explicit operator int64_t() const { return std::stoll(to_string()); }
explicit operator int() const { return std::stoi(to_string()); }
Bigint() : _data(1), _isNegative(false) {
}
// ReSharper disable once CppNonExplicitConvertingConstructor
Bigint(const int64_t &value) : _data(1) {
// NOLINT(*-explicit-constructor)
_isNegative = value < 0;
_data.front() = _isNegative ? -value : value;
}
Bigint(const Bigint &other) {
_data = other._data;
_isNegative = other._isNegative;
}
// ReSharper disable once CppNonExplicitConvertingConstructor
Bigint(const std::string &value) {
// NOLINT(*-explicit-constructor)
_isNegative = value.front() == '-';
int128_t r = value.size(), l = r - _len;
for (uint64_t val; l >= _isNegative; l -= _len, r -= _len) {
#if __cplusplus < 201700L
val = 0;
for (int128_t i = l; i < r; ++i)
val = val * 10 + value[i] - '0';
#else
std::from_chars(value.data() + l, value.data() + r, val);
#endif
_data.emplace_back(val);
}
#if __cplusplus < 201700L
if (r > _isNegative) {
uint64_t val = 0;
#else
if (uint64_t val; r > _isNegative) {
#endif
#if __cplusplus < 201700L
for (int128_t i = _isNegative; i < r; ++i)
val = val * 10 + value[i] - '0';
#else
std::from_chars(value.data() + _isNegative, value.data() + r, val);
#endif
_data.emplace_back(val);
}
}
friend std::istream &operator>>(std::istream &is, Bigint &other) {
std::string s;
is >> s;
other = Bigint(s);
return is;
}
[[nodiscard]] std::string to_string() const {
std::ostringstream ss;
if (_isNegative)
ss.put('-');
bool isTrimming = true;
for (size_t i = _data.size() - 1; i > 0; --i) {
if (_data[i] == 0 and isTrimming)
continue;
if (isTrimming) {
isTrimming = false;
ss << _data[i];
continue;
}
ss << std::setfill('0') << std::setw(_len) << _data[i];
}
if (not isTrimming)
ss << std::setfill('0') << std::setw(_len);
ss << _data.front();
return ss.str();
}
friend std::ostream &operator<<(std::ostream &os, const Bigint &value) {
os << value.to_string();
return os;
}
private:
template<typename T>
static int compare(const T &left, const T &right) {
if (left > right)
return 1;
if (left < right)
return -1;
return 0;
}
int compare(const Bigint &other) const {
const auto &NegativeCheck = [](const int &cmp, const bool &isNegative) {
if (isNegative) // 符号相同,负数越长越小,正数越长越大
return cmp == 1 ? -1 : 1;
return cmp;
};
if (_isNegative != other._isNegative) // 不同号的情况下,负数明显更小
return _isNegative ? -1 : 1;
auto cmp = compare(_data.size(), other._data.size());
if (cmp != 0)
return NegativeCheck(cmp, _isNegative);
for (int128_t i = _data.size() - 1; i >= 0; --i) {
cmp = compare(_data[i], other._data[i]);
if (cmp == 0)
continue;
return NegativeCheck(cmp, _isNegative);
}
return 0;
}
public:
#if __cplusplus >= 202000L
std::strong_ordering operator<=>(const Bigint &other) const {
switch (compare(other)) {
case 1: return std::strong_ordering::greater;
case 0: return std::strong_ordering::equal;
default: return std::strong_ordering::less;
}
}
bool operator==(const Bigint &other) const = default;
#else
bool operator <(const Bigint &other) const {
return compare(other) < 0;
}
bool operator <=(const Bigint &other) const {
return compare(other) <= 0;
}
bool operator >(const Bigint &other) const {
return compare(other) > 0;
}
bool operator >=(const Bigint &other) const {
return compare(other) >= 0;
}
bool operator==(const Bigint &other) const {
return _isNegative == other._isNegative and _data == other._data;
}
bool operator !=(const Bigint &other) const {
return not this->operator==(other);
}
#endif
// 取负数
Bigint operator-() const { return Bigint(_data, not _isNegative); }
bool is_odd() const { return _data.front() & 1; }
bool is_even() const { return not is_odd(); }
Bigint operator+(const Bigint &other) const {
if (_isNegative != other._isNegative)
return _isNegative
? Bigint(other) - Bigint(_data, false)
: operator-(Bigint(other._data, false));
int128_t carry = 0;
const auto max_size = std::max(_data.size(), other._data.size());
auto backup = *this;
Bigint result = other;
backup._data.resize(max_size, 0);
result._data.resize(max_size, 0);
for (int i = 0; i < max_size; ++i) {
const auto tmp = carry + backup._data[i] + result._data[i];
result._data[i] = tmp % _base;
carry = (tmp - result._data[i]) / _base;
}
return result;
}
Bigint operator+=(const Bigint &other) { return *this = *this + other; }
Bigint operator*(const Bigint &other) const {
if (this->to_string() == "0" or other.to_string() == "0")
return 0;
Bigint result(std::vector<uint64_t>(0), false);
int128_t carry = 0;
for (size_t i = 0; i < _data.size(); i++) {
Bigint each_data(std::vector<uint64_t>(i), false);
for (const auto &j: other._data) {
const auto tmp = static_cast<int128_t>(_data[i]) * j + carry;
each_data._data.emplace_back(tmp % _base);
carry = tmp / _base;
}
if (carry != 0) {
each_data._data.emplace_back(carry % _base);
carry = 0;
}
result += each_data;
}
return Bigint(result._data, _isNegative != other._isNegative);
}
Bigint operator*=(const Bigint &other) { return *this = *this * other; }
Bigint operator-(const Bigint &other) const {
if (_isNegative != other._isNegative)
return *this + Bigint(other._data, _isNegative);
if (_isNegative) // (-a) - (-b) => (-a) + b => b - a
return Bigint(other._data, false) - Bigint(_data, false);
const bool isNegative = *this < other; // 小减大,必然是负号,反之不是
const auto &bigSide = isNegative ? other : *this;
const auto &smallSide = isNegative ? *this : other;
Bigint result(std::vector<uint64_t>(0), isNegative);
int128_t carry = 0;
for (size_t i = 0; i < smallSide._data.size(); ++i) {
auto tmp = carry + bigSide._data[i] - smallSide._data[i];
carry = 0;
if (tmp < 0) {
carry = -1;
tmp += _base;
}
result._data.emplace_back(tmp);
}
for (size_t i = result._data.size(); i < bigSide._data.size(); ++i) {
const auto tmp = carry + bigSide._data[i];
carry = 0;
result._data.emplace_back(tmp);
}
if (carry != 0) // 借多的要还回去
result._data.back() -= carry;
while (result._data.size() > 1 and result._data.back() == 0)
result._data.pop_back();
return result;
}
Bigint operator-=(const Bigint &other) { return *this = *this - other; }
Bigint operator/(const Bigint &other) const {
Bigint modulo;
return div_mod(other, modulo);
}
Bigint operator/=(const Bigint &other) { return *this = *this / other; }
Bigint operator%(const Bigint &other) const {
Bigint modulo;
div_mod(other, modulo);
return modulo;
}
Bigint operator%=(const Bigint &other) { return *this = *this % other; }
Bigint operator<<(const Bigint &other) const {
Bigint base = 2, power = other;
return *this * pow(base, power);
}
Bigint operator<<=(const Bigint &other) { return *this = *this << other; }
Bigint operator>>(const Bigint &other) const {
Bigint base = 2, power = other;
return *this / pow(base, power);
}
Bigint operator>>=(const Bigint &other) { return *this = *this >> other; }
// 前自增
Bigint &operator++() {
*this += 1;
return *this;
}
// 后自增
Bigint operator++(int) {
auto temp = *this;
++*this;
return temp;
}
// 前自减
Bigint &operator--() {
*this -= 1;
return *this;
}
// 后自减
Bigint operator--(int) {
auto temp = *this;
--*this;
return temp;
}
};
#if __cplusplus >= 202000
// C++20 的 format 支持
template<>
struct std::formatter<Bigint> {
constexpr static auto parse(const std::format_parse_context &ctx) {
return ctx.begin();
}
static auto format(const Bigint &number, std::format_context &ctx) {
return std::format_to(ctx.out(), "{}", number.to_string());
}
};
#endif
using Int = Bigint;
#pragma endregion
#pragma endregion
using namespace std;
#define T_CASE 0
auto solve() -> void {
Int a, b;
cin >> a >> b;
println("{}", a + b);
println("{}", a - b);
println("{}", a * b);
println("{}", a / b);
println("{}", a % b);
}
auto main() -> signed {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int64_t t{1};
#if T_CASE
cin >> t;
#endif
while (t--)
solve();
return 0;
}字符串简单处理套件
#include <bits/stdc++.h>
class PalindromeHelper {
std::string string_;
size_t n;
std::vector<size_t> pow_, hash_, rhash_;
// [1, n] [l, r]
size_t get_hash(int l, int r) const {
assert(l <= r);
return hash_[r] - hash_[l - 1] * pow_[r - l + 1];
}
// [1, n] [l, r]
size_t get_rhash(int l, int r) const {
assert(l <= r);
return rhash_[n - l + 1] - rhash_[n - r] * pow_[r - l + 1];
}
public:
PalindromeHelper(std::string_view string, size_t prime = 233) : string_(string) {
n = string.length();
hash_.resize(n + 1);
rhash_.resize(n + 1);
pow_.resize(n + 1);
pow_[0] = 1;
hash_[0] = rhash_[0] = 0;
for (size_t i = 0; i < n; ++i) {
hash_[i + 1] = hash_[i] * prime + string[i];
rhash_[i + 1] = rhash_[i] * prime + string[n - i - 1];
pow_[i + 1] = pow_[i] * prime;
}
}
// 0-index
bool is_palindrome(int l, int r) const {
return get_hash(l + 1, r + 1) == get_rhash(l + 1, r + 1);
}
std::string_view longest_palindrome() {
if (string_.empty())
return "";
size_t max_length = 1, start = 0;
for (size_t r = 0, current = 0; r < n; ++r) {
for (auto length = std::min(current + 2, r + 1); length; --length) {
size_t l = r - length + 1;
if (not is_palindrome(l, r))
continue;
current = length;
break;
}
// 更新全局最长回文
if (current > max_length) {
max_length = current;
start = r - current + 1;
}
}
return std::string_view(string_.data() + start, max_length);
}
};
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s;
cin >> s;
PalindromeHelper helper(s);
cout << helper.longest_palindrome().length() << '\n';
}128位整形
#include <bits/stdc++.h>
using i128 [[maybe_unused]] = __int128;
const i128 &INT128_MAX = (i128(INT64_MAX) << 64) | UINT64_MAX;
const i128 &INT128_MIN = ~INT128_MAX;
i128 operator ""_i(const unsigned long long &value) {
return i128(value);
}
i128 operator ""_i(const char *str, std::size_t len) {
bool f = str[0] == '-';
if (not std::all_of(str + f, str + len, isdigit))
throw std::invalid_argument("无法转换为整数");
i128 value = 0;
for (int i = 0 + f; i < len; ++i)
value = (value << 3) + (value << 1) + (str[i] ^ '0');
return f ? -value : value;
}
std::istream &operator>>(std::istream &is, i128 &value) {
value = 0;
bool isNegative = false;
int c = is.get();
while (not isdigit(c)) {
if (c == '-')
isNegative = true;
c = is.get();
}
while (isdigit(c)) {
value = (value << 3) + (value << 1) + (c ^ '0');
c = is.get();
}
if (isNegative)
value = -value;
return is;
}
std::ostream &operator<<(std::ostream &os, i128 value) {
if (value == 0) {
os.put('0');
return os;
}
static char sta[40];
unsigned char top = 0;
if (value < 0) {
sta[top++] = static_cast<char>(-(value % 10));
value /= 10;
value = ~value + 1;
os.put('-');
}
for (; value; value /= 10)
sta[top++] = static_cast<char>(value % 10);
for (; top--;)
os.put(static_cast<char>(sta[top] ^ '0'));
return os;
}简单矩阵及其矩阵的运算
#include <bits/stdc++.h>
using namespace std;
template <typename T> class Matrix {
vector<vector<T>> mat;
size_t d;
public:
Matrix(size_t n) : mat(n, vector<T>(n, 0)) {
d = n;
for (size_t i = 0; i < n; ++i)
mat[i][i] = 1;
}
Matrix(const vector<vector<T>> &&val) : mat(val), d(val.size()) {}
Matrix(const vector<vector<T>> &val) : mat(val), d(val.size()) {}
Matrix operator+(const Matrix &other) {
Matrix res = other;
for (size_t i = 0; i < d; ++i)
for (size_t j = 0; j < d; ++j)
res.mat[i][j] = mat[i][j] + other.mat[i][j];
return res;
}
Matrix operator+=(const Matrix &other) {
for (size_t i = 0; i < d; ++i)
for (size_t j = 0; j < d; ++j)
mat[i][j] += other.mat[i][j];
return mat;
}
Matrix operator-(const Matrix &other) {
Matrix res = other;
for (size_t i = 0; i < d; ++i)
for (size_t j = 0; j < d; ++j)
res.mat[i][j] = mat[i][j] - other.mat[i][j];
return res;
}
Matrix operator-=(const Matrix &other) {
for (size_t i = 0; i < d; ++i)
for (size_t j = 0; j < d; ++j)
mat[i][j] -= other.mat[i][j];
return mat;
}
Matrix operator*(const Matrix &other) {
Matrix res = other;
for (size_t i = 0; i < d; ++i)
for (size_t j = 0; j < d; ++j) {
res.mat[i][j] = 0;
for (size_t k = 0; k < d; ++k)
res.mat[i][j] += mat[i][k] * other.mat[k][j];
}
return res;
}
Matrix operator*=(const Matrix &other) {
Matrix res = other;
for (size_t i = 0; i < d; ++i)
for (size_t j = 0; j < d; ++j) {
res.mat[i][j] = 0;
for (size_t k = 0; k < d; ++k)
res.mat[i][j] += mat[i][k] * other.mat[k][j];
}
mat = res.mat;
return res;
}
Matrix mul(const Matrix &other, const T mod) {
Matrix res = other;
for (size_t i = 0; i < d; ++i)
for (size_t j = 0; j < d; ++j) {
res.mat[i][j] = 0;
for (size_t k = 0; k < d; ++k)
res.mat[i][j] += mat[i][k] * other.mat[k][j] % mod;
res.mat[i][j] %= mod;
}
return res;
}
Matrix operator^(size_t power) {
Matrix res(d), base = *this;
while (power) {
if (power & 1)
res = res * base;
power >>= 1;
base = base * base;
}
return res;
}
Matrix pow(size_t power, const T mod) {
Matrix res(d), base = *this;
while (power) {
if (power & 1)
res = res.mul(base, mod);
power >>= 1;
base = base.mul(base, mod);
}
return res;
}
T at(const size_t x, const size_t y) { return mat[x][y]; }
};
using i64 = long long;
using matrix = vector<vector<i64>>;
constexpr i64 mod = 1000000007;rust仿java Scanner的输入
// 输入用
use std::{
io::{stdin, Read},
vec,
};
pub struct Scanner {
stream: std::io::Stdin,
}
impl Scanner {
pub fn new(istream: std::io::Stdin) -> Self {
Self { stream: istream }
}
pub fn skip_line(&mut self) {
let _ = std::io::stdin().read_line(&mut String::new());
}
pub fn read_char(&mut self) -> char {
let mut byte = [0; 1];
let _ = self.stream.read(&mut byte);
return char::from(byte[0]);
}
pub fn next_char(&mut self) -> char {
let mut c: char = self.read_char();
while char::is_whitespace(c) {
c = self.read_char();
}
return c;
}
pub fn next_line(&mut self) -> String {
let mut str = String::new();
let _ = std::io::stdin().read_line(&mut str);
str.pop();
return str;
}
fn read_line_i128(&mut self) -> Vec<i128> {
let mut line = self.next_line();
while line.is_empty() {
line = self.next_line();
}
let inputs: Vec<i128> = line
.trim()
.split_whitespace()
.map(|x| x.parse().expect(""))
.collect();
return inputs;
}
fn read_line_f64(&mut self) -> Vec<f64> {
let mut line = self.next_line();
while line.is_empty() {
line = self.next_line();
}
let inputs: Vec<f64> = line
.trim()
.split_whitespace()
.map(|x| x.parse().expect(""))
.collect();
return inputs;
}
pub fn next_i128(&mut self) -> i128 {
let mut res = 0;
let mut is_negative = false;
let mut chr = self.read_char();
while !char::is_ascii_digit(&chr) {
if chr == '-' {
is_negative = true;
}
chr = self.read_char();
}
while char::is_ascii_digit(&chr) {
res = (res << 3) + (res << 1) + (chr as i128) - ('0' as i128);
chr = self.read_char();
}
return if is_negative { -res } else { res };
}
pub fn next_f64(&mut self) -> f64 {
let mut res = 0.0;
let mut i = 0.0;
let mut is_visted_dot = false;
let mut is_negative = false;
let mut chr = self.read_char();
while !char::is_ascii_digit(&chr) {
if chr == '-' {
is_negative = true;
}
if chr == '.' {
is_visted_dot = true;
}
chr = self.read_char();
}
while char::is_ascii_digit(&chr) && !is_visted_dot {
res = res * 10.0 + ((chr as i128) - ('0' as i128)) as f64;
chr = self.read_char();
}
if chr == '.' {
chr = self.read_char();
}
while char::is_ascii_digit(&chr) {
i = i * 0.1 + ((chr as i128) - ('0' as i128)) as f64;
chr = self.read_char();
}
let res = res + i * 0.1;
return if is_negative { -res } else { res };
}
pub fn next_f32(&mut self) -> f32 {
return self.next_f64() as f32;
}
pub fn next_i64(&mut self) -> i64 {
return self.next_i128() as i64;
}
pub fn next_i32(&mut self) -> i32 {
return self.next_i128() as i32;
}
pub fn next_i16(&mut self) -> i16 {
return self.next_i128() as i16;
}
}普通线段树
template<typename T>
struct SegmentTree {
SegmentTree(std::vector<T> data) : tree(data.size() << 2) {
n = data.size();
build(0, 0, n - 1, data);
}
// [l, r]
T query_range(long l, long r) {
return query_range(0, 0, n - 1, l, r);
}
private:
std::vector<T> tree;
long n;
void build(long index, long l, long r, std::vector<T> &data) {
if (l == r) {
tree[index] = data[l];
return;
}
auto mid = (l + r) >> 1;
auto lkid = index << 1 | 1;
auto rkid = lkid + 1;
build(lkid, l, mid, data);
build(rkid, mid + 1, r, data);
tree[index] = std::max(tree[lkid], tree[rkid]);
}
T query_range(long index, long l, long r, const long ql, const long qr) {
if (ql <= l and r <= qr)
return tree[index];
if (l == r)
return tree[index];
auto mid = (l + r) >> 1;
auto lkid = index << 1 | 1;
auto rkid = lkid + 1;
T result = std::numeric_limits<T>::min();
if (ql <= mid)
result = std::max(result, query_range(lkid, l, mid, ql, qr));
if (qr > mid)
result = std::max(result, query_range(rkid, mid + 1, r, ql, qr));
return result;
}
};zkw线段树
template<class T>
// 写在前头, xor 是 ^ 的别名,bitand 是 & 的别名,bitor 是 | 的别名
class segmentTree {
vector<T> tree, mark;
i64 N; // 子叶节点的个数(不足2的n次幂就补全)
public:
// zkw线段树
explicit segmentTree(const vector<T> &a) {
auto &&n = a.size();
// 补全为 2 的 n 次幂
for (N = 1; N < n; N <<= 1);
// 树和标记要开 2 的 n + 1 次幂的空间(参考满二叉树的节点数)
mark = vector<T>(N << 1, 0);
tree = mark;
// 子叶节点赋值(可以改为直接输入)
for (i64 &&i = 1; i <= n; ++i)
tree[i + N] = a[i - 1];
// 计算每个区间的值,一个区间的和的左孩子区间加右孩子区间
for (i64 i = N - 1; i; --i)
tree[i] = tree[i << 1] + tree[i << 1 bitor 1];
}
// 单点查询
T query_point(const i64 &index) {
// 偷个懒,直接用区间查询来查询单点
return query_range(index, index);
}
// 单点更新
void update_point(const i64 &x, const T &v) {
// 从子叶节点开始回溯到根节点,给他们加上v
for (auto &&i = x + N; i; i >>= 1)
tree[i] += v;
}
// 区间查询
T query_range(i64 l, i64 r) {
// 返回值,当前层任一节点为根的子树的节点数,左、右两边分别实际修改的区间长度
i64 res{0}, cnt{1}, cl{0}, cr{0};
// for(从子叶节点开始回溯(开区间),l + 1 < r,回溯)
for (l += N - 1, r += N + 1; l xor r xor 1; l >>= 1, r >>= 1, cnt <<= 1) {
// 利用标记快速计算
res += cl * mark[l] + cr * mark[r];
// l是偶数,即l是一个节点的左孩子
if (~l bitand 1) {
// 说明它的兄弟(右孩子)对答案有贡献
res += tree[l xor 1];
cl += cnt;
}
// r是奇数,即l是一个节点的右孩子
if (r bitand 1) {
// 说明它的兄弟(左孩子)对答案有贡献
res += tree[r xor 1];
cr += cnt;
}
}
// 回溯中遇到的标记也对答案有相应的贡献,根据查询区间长度计算
for (; l; l >>= 1, r >>= 1)
res += cl * mark[l] + cr * mark[r];
return res;
}
// 区间修改(加)
void update_range(i64 l, i64 r, const T &v) {
i64 cnt{1}, //cnt为以当前层任一节点为根的子树的节点数
cl{0}, cr{0}; //cl, cr 是左、右两边分别实际修改的区间长度
// for(从子叶节点开始回溯(开区间),l + 1 < r,回溯)
for (l += N - 1, r += N + 1; l xor r xor 1; l >>= 1, r >>= 1, cnt <<= 1) {
tree[l] += cl * v; // 更新节点值
tree[r] += cr * v; // 更新节点值
// l是偶数,即l是一个节点的左孩子
if (~l bitand 1) {
// 说明它的兄弟(右孩子)在添加区间内
tree[l xor 1] += cnt * v;
// 标记传递
mark[l xor 1] += v;
cl += cnt;
}
// r是奇数,即l是一个节点的右孩子
if (r bitand 1) {
// 说明它的兄弟(左孩子)在添加区间内
tree[r xor 1] += cnt * v;
// 标记传递
mark[r xor 1] += v;
cr += cnt;
}
}
// 回溯,更新父节点,根据查询区间长度计算
for (; l; l >>= 1, r >>= 1) {
tree[l] += cl * v;
tree[r] += cr * v;
}
}
};kmp系列
// 求next数组
vector<int> getNext(const string &s) {
int n = parse<int>(s.length());
vector<int> next(n, 0);
for (int i = 1, j = 0; i < n; ++i) {
while (j and s[i] != s[j])
j = next[j - 1];
if (s[i] == s[j])
++j;
next[i] = j;
}
return next;
}
// 求原串 container 包含多少个子串 substr
int kmp_counter(const string &container, const string &substr,
auto&& next = vector<int>()) {
if (next.empty())
next = std::move(getNext(substr));
int n = parse<int>(container.length()), m = parse<int>(substr.length()), ans{};
for (int i = 0, j = 0; i < n; ++i) {
while (j and container[i] != substr[j])
j = next[j - 1];
if (container[i] == substr[j])
++j;
if (j == m) {
ans++;
j = 0;
}
}
return ans;
}
// 求原串 container 中子串 substr 出现的第一个位置
size_t kmp_searcher(string &container, const string &substr,
auto&& next = vector<int>(), const int &l = 0) {
if (next.empty())
next = std::move(getNext(substr));
int n = parse<int>(container.length()), m = parse<int>(substr.length());
for (int i = l, j = 0; i < n; ++i) {
while (j and container[i] != substr[j])
j = next[j - 1];
if (container[i] == substr[j])
++j;
if (j == m)
return i - m + 1;
}
return string::npos;
}并查集
template<typename T>
class UnionFindSet {
std::vector<T> trees, size;
public:
explicit UnionFindSet(T len) : trees(len << 1), size((len << 1), 1) {
std::iota(trees.begin(), trees.begin() + len, len);
std::iota(trees.begin() + len, trees.end(), len);
}
T find(const T &x) {
return trees[x] == x ? x : trees[x] = find(trees[x]);
}
void unite(const T &x, const T &y) {
T &&fx = find(x), &&fy = find(y);
if (fx == fy) return;
if (size[fx] < size[fy]) std::swap(fx, fy);
trees[fy] = fx;
size[fx] += size[fy];
}
void erase(const T &x) {
--size[find(x)];
trees[x] = x;
}
void move(const T &x, const T &y) {
T &&fx = find(x), &&fy = find(y);
if (fx == fy) return;
trees[x] = fy;
--size[fx], ++size[fy];
}
bool isSameSet(const T &x, const T &y) {
return find(x) == find(y);
}
};ST表
template<typename T>
class SparseTable {
private:
vector<vector<T> > st;
function<const T &(const T &, const T &)> func;
void init(const vector<T> &input) {
size_t n = input.size() - 1;
st.resize(n + 1);
int m = int(log2(n)) + 2;
for (int i = 0; i <= n; i++) {
st[i].resize(m);
st[i][0] = input[i];
}
for (int j = 1; 1 << j <= n; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
st[i][j] = func(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
public:
[[maybe_unused]] explicit SparseTable(const vector<T> &input, const bool &isMax = true) {
function<const T &(const T &, const T &)> &&f = [&isMax](const T &a, const T &b) {
return isMax ? max(a, b) : min(a, b);
};
func = f;
init(input);
}
[[maybe_unused]] SparseTable(const vector<T> &input, function<const T &(const T &, const T &)> f) {
func = f;
init(input);
}
[[maybe_unused]] T search(const size_t &l, const size_t &r) {
int k = int(log2(r - l + 1));
return func(st[l][k], st[r - (1 << k) + 1][k]);
}
};Rust Scanner
// 输入用
pub struct Scanner {
stream: std::io::Stdin,
}
impl Scanner {
pub fn new(istream: std::io::Stdin) -> Self {
Self {
stream: istream,
}
}
pub fn skip_line(&mut self) {
let _ = self.stream.read_line(&mut String::new());
}
pub fn read_char(&mut self) -> Option<char> {
let mut byte = [0; 1];
match self.stream.read(&mut byte) {
Ok(0) => None, // EOF
Ok(_) => Some(char::from(byte[0])),
Err(_) => None, // Error reading
}
}
pub fn next_char(&mut self) -> Option<char> {
let mut c = self.read_char()?;
while c.is_whitespace() {
c = self.read_char()?;
}
Some(c)
}
pub fn next(&mut self) -> Option<String> {
let mut c = self.read_char()?;
loop {
if !c.is_whitespace() {
break;
}
c = self.read_char()?;
}
let mut buffer = String::new();
loop {
buffer.push(c);
c = self.read_char()?;
if c.is_whitespace() {
break;
}
}
return if buffer.is_empty() { None } else { Some(buffer) };
}
pub fn next_line(&mut self) -> Option<String> {
let mut buffer = String::new();
match self.stream.read_line(&mut buffer) {
Ok(0) => None, // EOF
Ok(_) => Some(buffer.trim_end().to_string()),
Err(_) => None, // Error reading
}
}
pub fn read_line_i128(&mut self) -> Option<Vec<i128>> {
let line = self.next_line()?;
if line.is_empty() {
return None;
}
let inputs: Vec<i128> = line
.split_whitespace()
.map(|x| x.parse().ok())
.collect::<Option<Vec<i128>>>()?;
Some(inputs)
}
pub fn read_line_f64(&mut self) -> Option<Vec<f64>> {
let line = self.next_line()?;
if line.is_empty() {
return None;
}
let inputs: Vec<f64> = line
.split_whitespace()
.map(|x| x.parse().ok())
.collect::<Option<Vec<f64>>>()?;
Some(inputs)
}
pub fn next_i128(&mut self) -> Option<i128> {
let mut res = 0;
let mut is_negative = false;
let mut chr = self.read_char()?;
while !chr.is_ascii_digit() {
if chr == '-' {
is_negative = true;
}
chr = self.read_char()?;
}
while chr.is_ascii_digit() {
res = (res << 3) + (res << 1) + (chr as i128) - ('0' as i128);
chr = self.read_char()?;
}
Some(if is_negative { -res } else { res })
}
pub fn next_f64(&mut self) -> Option<f64> {
let mut res = 0.0;
let mut i = 0.0;
let mut is_visited_dot = false;
let mut is_negative = false;
let mut chr = self.read_char()?;
while !chr.is_ascii_digit() {
if chr == '-' {
is_negative = true;
}
if chr == '.' {
is_visited_dot = true;
}
chr = self.read_char()?;
}
while chr.is_ascii_digit() && !is_visited_dot {
res = res * 10.0 + ((chr as i128) - ('0' as i128)) as f64;
chr = self.read_char()?;
}
if chr == '.' {
chr = self.read_char()?;
}
while chr.is_ascii_digit() {
i = i * 0.1 + ((chr as i128) - ('0' as i128)) as f64;
chr = self.read_char()?;
}
Some(if is_negative { -res - i } else { res + i })
}
pub fn next_f32(&mut self) -> Option<f32> {
self.next_f64().map(|v| v as f32)
}
pub fn next_i64(&mut self) -> Option<i64> {
self.next_i128().map(|v| v as i64)
}
pub fn next_i32(&mut self) -> Option<i32> {
self.next_i128().map(|v| v as i32)
}
pub fn next_i16(&mut self) -> Option<i16> {
self.next_i128().map(|v| v as i16)
}
}好用的模板
https://winterl-blog.netlify.app/2024/11/18/好用的模板/