QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#765605 | #8049. Equal Sums | lizhu6 | TL | 0ms | 3812kb | C++20 | 13.4kb | 2024-11-20 14:47:55 | 2024-11-20 14:47:55 |
Judging History
answer
#pragma GCC optimize("-Ofast")
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cassert>
#include <numeric>
using namespace std;
typedef long long LL;
constexpr int N = 1010;
constexpr int mod = 998244353;
template <typename Tp1, typename Tp2> inline void cmax(Tp1 &A, const Tp2 &B) { if (A < B) A = B; return; }
template <typename Tp1, typename Tp2> inline void cmin(Tp1 &A, const Tp2 &B) { if (A > B) A = B; return; }
template <typename Tp1, typename Tp2, int mod = ::mod> inline void ad(Tp1 &A, const Tp2 &B) { A = (A + B) % mod; return; }
template <typename Tp1, typename Tp2, int mod = ::mod> inline void sb(Tp1 &A, const Tp2 &B) { A = (A + mod - B) % mod; return; }
int n, m;
struct par
{
par() = default;
par(int _x, int _y) : x(_x), y(_y) { }
bool operator<(const par Q) const { return x != Q.x ? x < Q.x : y < Q.y; }
bool operator==(const par Q) const { return x == Q.x && y == Q.y; }
bool operator>(const par Q) const { return x != Q.x ? x > Q.x : y > Q.y; }
int x, y;
} lx[N], ly[N];
struct poly
{
typedef poly this_type;
static constexpr int mod = 998244353;
static constexpr int ebase = 119;
std::vector<long long> poly_base;
static constexpr int qp[] = { 15311432, 267099868,
733596141, 565042129, 363395222, 996173970, 24514907,
629671588, 968855178, 666702199, 350007156, 63912897,
584193783, 258648936, 166035806, 476477967, 781712469,
922799308, 452798380, 929031873, 372528824, 911660635,
998244352, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static constexpr int qpinv[] = { 469870224, 382752275,
428961804, 950391366, 704923114, 121392023, 3707709,
283043518, 708402881, 814576206, 358024708, 129292727,
335559352, 381598368, 685443576, 304459705, 135236158,
609441965, 87557064, 337190230, 509520358, 86583718,
998244352, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static long long builtin_quick_pow(
long long base, long long ind)
{
LL res = 1;
while (ind)
{
if (ind & 1ll)
res = res * base % mod;
ind >>= 1;
base = base * base % mod;
}
return res;
}
inline long long& operator[](const std::size_t pos)
{
return poly_base[pos];
}
auto at(const std::size_t pos)
{
return poly_base.at(pos);
}
inline const long long& operator[](
const std::size_t pos) const
{
return poly_base[pos];
}
inline long long get(const std::size_t pos) const noexcept
{
return pos < poly_base.size() ? poly_base[pos] : 0;
}
void del_zero()
{
while (!poly_base.back())
poly_base.pop_back();
}
poly() = default;
poly(std::initializer_list<long long> _list)
: poly_base(_list)
{
std::reverse(poly_base.begin(), poly_base.end());
while (!poly_base.back())
poly_base.pop_back();
}
poly(std::vector<long long> _vec)
: poly_base(std::move(_vec))
{
}
explicit poly(int _siz, LL _val = 0)
: poly_base(
std::move(std::vector<long long>(_siz, _val)))
{
}
// size() - 1 is the poly's highest index
inline std::size_t size() const
{
return poly_base.size();
}
inline void resize(std::size_t new_size, LL new_val = LL())
{
return poly_base.resize(new_size, new_val);
}
inline bool empty() const { return poly_base.empty(); }
poly operator+(const this_type& Q) const
{
poly res;
res.poly_base.resize(std::max(this->size(), Q.size()));
for (std::size_t i = 0; i != size(); i++)
(res.operator[](i) += operator[](i)) %= mod;
for (std::size_t i = 0; i != Q.size(); i++)
(res.operator[](i) += Q[i]) %= mod;
return res;
}
poly& operator+=(const this_type& Q)
{
poly_base.resize(std::max(this->size(), Q.size()));
for (std::size_t i = 0; i != Q.size(); i++)
(this->operator[](i) += Q[i]) %= mod;
return *this;
}
poly operator-(const this_type& Q) const
{
poly res;
res.poly_base.resize(std::max(this->size(), Q.size()));
for (std::size_t i = 0; i != size(); i++)
(res.operator[](i) += operator[](i)) %= mod;
for (std::size_t i = 0; i != Q.size(); i++)
(res.operator[](i) -= Q[i]) %= mod,
(res.operator[](i) += mod) %= mod;
res.del_zero();
return res;
}
poly& operator-=(const this_type& Q)
{
poly_base.resize(std::max(this->size(), Q.size()));
for (std::size_t i = 0; i != size(); i++)
(this->operator[](i) += mod - Q[i]) %= mod;
del_zero();
return *this;
}
struct DFT_BASE
{
void operator()(const std::size_t _len,
std::vector<long long>& _con) const
{
if (_len == 1)
return;
const std::size_t _half = _len >> 1;
std::vector<long long> _con1(_half), _con2(_half);
for (std::size_t i = 0; i != _half; i++)
{
_con1[i] = _con[i << 1];
_con2[i] = _con[i << 1 | 1];
}
this->operator()(_half, _con1);
this->operator()(_half, _con2);
long long w = 1ll;
const long long w0
= qp[__builtin_ctz((mod - 1) / _len / ebase)];
for (std::size_t i = 0; i != _half;
i++, (w *= w0) %= mod)
{
_con[i] = (_con1[i] + w * _con2[i] % mod) % mod;
_con[i + _half]
= (_con1[i] - w * _con2[i] % mod + mod) % mod;
}
return;
}
};
struct IDFT_BASE
{
void operator()(const std::size_t _len,
std::vector<long long>& _con) const
{
if (_len == 1)
return;
const std::size_t _half = _len >> 1;
std::vector<long long> _con1(_half), _con2(_half);
for (std::size_t i = 0; i != _half; i++)
{
_con1[i] = _con[i << 1];
_con2[i] = _con[i << 1 | 1];
}
this->operator()(_half, _con1);
this->operator()(_half, _con2);
long long w = 1ll;
const long long w0
= qpinv[__builtin_ctz((mod - 1) / _len / ebase)];
for (std::size_t i = 0; i != _half;
i++, w = w * w0 % mod)
{
_con[i] = (_con1[i] + w * _con2[i] % mod) % mod;
_con[i + _half]
= (_con1[i] - w * _con2[i] % mod + mod) % mod;
}
return;
}
};
inline int get_len(int limit) const
{
int len;
for (len = 1; len < limit; len <<= 1)
;
return len;
}
void DFT(int limit)
{
if (limit != (int)poly_base.size())
poly_base.resize(limit);
DFT_BASE()(limit, poly_base);
return;
}
void IDFT(int limit)
{ // suppose that the len = 2^k
IDFT_BASE()(limit, poly_base);
const LL inv = builtin_quick_pow(limit, mod - 2);
for (auto& val : poly_base)
val = val * inv % mod;
}
poly operator*(const this_type& Q) const
{
if (this->empty() && Q.empty())
return poly();
int tar = size() + Q.size() - 1u;
int len;
for (len = 1; len < tar; len <<= 1)
;
std::vector<long long> res(len), lft(len), rht(len);
copy(poly_base.begin(), poly_base.end(), lft.begin());
copy(Q.poly_base.begin(), Q.poly_base.end(),
rht.begin());
DFT_BASE()(len, lft);
DFT_BASE()(len, rht);
for (int i = 0; i != len; i++)
res[i] = lft[i] * rht[i] % mod;
IDFT_BASE()(len, res);
// while (res.back() == 0) res.pop_back();
const long long leninv
= builtin_quick_pow(len, mod - 2);
for (long long& val : res)
val = val * leninv % mod;
res.resize(tar);
return poly(res);
}
poly& operator*=(const this_type& Q)
{
auto res = *this * Q;
this->resize(res.size());
for (int i = 0; i != (int)size(); i++)
this->operator[](i) = res[i];
return *this;
}
inline poly& operator=(
const std::initializer_list<long long> _list)
{
poly_base = _list;
reverse(poly_base.begin(), poly_base.end());
del_zero();
return *this;
}
inline poly& operator=(const std::vector<long long> _vec)
{
poly_base = std::move(_vec);
return *this;
}
poly deri() const
{
if (size() <= 1u)
return poly();
std::vector<long long> res(size() - 1u);
const int siz = static_cast<int>(size());
for (int i = 0; i != siz - 1; i++)
res[i] = get(i + 1) * (i + 1) % mod;
return res;
}
poly& to_deri()
{
if (empty())
return *this;
const int siz = static_cast<int>(size());
for (int i = 0; i != siz - 1; i++)
this->operator[](i) = get(i) * (i + 1) % mod;
poly_base.pop_back();
return *this;
}
poly inte() const
{
if (empty())
return poly();
std::vector<long long> res(size() + 1u);
const int siz = static_cast<int>(size());
std::vector<long long> numinv(siz + 1);
numinv[1] = 1;
for (int i = 2; i <= siz; i++)
numinv[i] = (long long)(mod - mod / i)
* numinv[mod % i] % mod;
for (int i = 1; i <= siz; i++)
{
res[i] = get(i - 1) * numinv[i] % mod;
}
return poly(res);
}
poly& to_inte()
{
if (empty())
return *this;
const int siz = static_cast<int>(size());
std::vector<long long> numinv(siz + 1);
numinv[1] = 1;
for (int i = 2; i <= siz; i++)
numinv[i] = (long long)(mod - mod / i)
* numinv[mod % i] % mod;
this->poly_base.emplace_back(0);
for (int i = siz; i >= 1; i--)
{
this->operator[](i) = get(i - 1) * numinv[i] % mod;
}
this->operator[](0) = 0;
return *this;
}
poly inv() const
{
return inv((int)size());
}
poly inv(int len) const
{
if (len == 1)
{
return poly(vector<long long> { builtin_quick_pow(
this->operator[](0), mod - 2) });
}
poly lft = vector<long long>(
poly_base.begin(), poly_base.begin() + len);
poly rht = inv((len + 1) >> 1);
int glen = get_len(len << 1);
lft.DFT(glen);
rht.DFT(glen);
for (int i = 0; i != glen; i++)
lft[i] = rht[i] * (2ll - lft[i] * rht[i] % mod + mod)
% mod;
lft.IDFT(glen);
lft.resize(len);
return lft;
}
poly ln() const
{
auto res = inv() * deri();
res.resize(size());
res.to_inte();
res.resize(size());
return res;
}
poly exp() const { return exp((int)size()); }
poly exp(int len) const
{
if (len == 1)
{
return vector<long long> { 1 };
}
poly tmp = exp((len + 1) >> 1);
tmp.resize(len);
poly lntmp = tmp.ln();
lntmp.resize(len);
for (int i = 0; i != len; i++)
lntmp[i]
= (this->operator[](i) - lntmp[i] + mod) % mod;
int glen = get_len(len << 1);
tmp.DFT(glen);
lntmp.DFT(glen);
for (int i = 0; i != glen; i++)
tmp[i] = tmp[i] * (lntmp[i] + 1) % mod;
tmp.IDFT(glen);
tmp.resize(len);
return tmp;
}
poly pow(int k) const
{
poly tmp = ln();
for (auto& val : tmp.poly_base)
val = val * k % mod;
return tmp.exp();
}
poly operator/(const poly &other) const
{
poly lft = *this, rht = other;
reverse(lft.poly_base.begin(), lft.poly_base.end());
reverse(rht.poly_base.begin(), rht.poly_base.end());
const int tar = lft.size() - rht.size() + 1;
rht.resize(tar);
poly res = lft * rht.inv();
res.resize(tar);
reverse(res.poly_base.begin(), res.poly_base.end());
return res;
}
pair<poly, poly> div_mod(const poly &other) const
{
poly lft = *this, rht = other;
reverse(lft.poly_base.begin(), lft.poly_base.end());
reverse(rht.poly_base.begin(), rht.poly_base.end());
const int tar = lft.size() - rht.size() + 1;
rht.resize(tar);
poly res1 = lft * rht.inv();
res1.resize(tar);
reverse(res1.poly_base.begin(), res1.poly_base.end());
poly res2 = *this - res1 * other;
res2.resize(other.size() - 1);
return make_pair(std::move(res1), std::move(res2));
}
inline friend std::istream& operator>>(
std::istream& is, poly& val)
{
for (long long& _val : val.poly_base)
is >> _val;
return is;
}
inline friend std::ostream& operator<<(
std::ostream& os, const poly& val)
{
for (const long long _val : val.poly_base)
os << _val << ' ';
return os;
}
} X[N], Y[N];
int xx[N], yy[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> lx[i].x >> lx[i].y;
for (int i = 1; i <= m; i++) cin >> ly[i].x >> ly[i].y;
for (int i = 1; i <= n; i++)
{
xx[i] = lx[i].x;
X[i].resize(lx[i].y - lx[i].x + 1, 1);
}
for (int i = 1; i <= m; i++)
{
yy[i] = ly[i].x;
Y[i].resize(ly[i].y - ly[i].x + 1, 1);
}
for (int i = 2; i <= n; i++)
X[i] = X[i] * X[i - 1], xx[i] += xx[i - 1];
for (int i = 2; i <= m; i++)
Y[i] = Y[i] * Y[i - 1], yy[i] += yy[i - 1];
for (int i = 1; i <= n; i++, cout << '\n')
for (int j = 1; j <= m; j++)
{
LL ans = 0;
const auto siz = min(X[i].size(), Y[j].size());
if (X[i].size() <= Y[j].size())
{
for (std::size_t p = 0u; p != siz; p++)
ad(ans, X[i].get(p) * Y[j].get(p + xx[i] - yy[j]));
}
else
{
for (std::size_t p = 0u; p != siz; p++)
ad(ans, Y[j].get(p) * X[i].get(p + yy[j] - xx[i]));
}
cout << ans << ' ';
}
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 0ms
memory: 3812kb
input:
2 3 1 2 2 3 1 4 2 2 1 3
output:
2 0 0 3 4 4
result:
ok 6 numbers
Test #2:
score: -100
Time Limit Exceeded
input:
500 500 19 458 1 480 7 485 50 461 12 476 15 461 48 466 40 453 46 467 9 458 27 478 26 472 46 459 29 490 6 500 17 487 48 484 28 472 28 459 25 480 4 491 29 481 36 460 2 491 44 499 22 473 20 458 4 483 27 471 2 496 11 461 43 450 2 478 37 466 15 459 42 482 7 451 19 455 2 453 47 475 48 450 1 474 46 471 9 4...