QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#581057 | #9380. Match | shiqiaqiaya | AC ✓ | 67ms | 4200kb | C++17 | 14.2kb | 2024-09-22 05:57:40 | 2024-09-22 05:57:40 |
Judging History
answer
#include<bits/stdc++.h>
using namespace std;
#define int long long
template <class T, class ... A>
void debug(const T & t, const A & ... a) { cerr << "[" << t, ((cerr << ", " << a), ...), cerr << "]\n"; }
mt19937_64 rd(time(0));
constexpr int mod = 998244353, g[2] = {332748118, 3};
constexpr int MOD[] = {998244353, 1004535809, 754974721, 469762049}, G[][2] = {{332748118, 3}, {334845270, 3}, {617706590, 11}, {156587350, 3}};
auto binpow = [](int a, int b, int mod, int res = 1) { // 模数为质数,求逆元,可以对次幂 mod (mod - 1) 加速
for (a %= mod; b; b >>= 1, (a *= a) %= mod) {
if (b & 1) {
(res *= a) %= mod;
}
}
return res;
};
auto Cipolla = [](int n, int mod) -> set<int> { // size() 为 0 无解,为 1 相同解,为 2 两个解
if (!(n %= mod) || mod == 2) return {mod == 2};
if (binpow(n, mod - 1 >> 1, mod) == mod - 1) return {};
while (true) {
int a = rd() % mod, w = (a * a - n + mod) % mod;
if (binpow(w, mod - 1 >> 1, mod) == mod - 1) {
return [&](array<int, 2> a, int b, array<int, 2> res = {1, 0}) {
auto mul = [&](auto & a, auto & b) {
a = {(a[0] * b[0] + a[1] * b[1] % mod * w) % mod, (a[0] * b[1] + a[1] * b[0]) % mod};
};
for ( ; b; b >>= 1, mul(a, a)) {
if (b & 1) mul(res, a);
}
return res[0] << 1 == mod ? set{res[0]} : set{res[0], mod - res[0]};
} ({a, 1}, mod + 1 >> 1);
}
}
};
template <int mod = mod, const int *g = g>
struct Poly : vector<int> {
int deg;
static vector Inv;
static array<vector, 2> W;
Poly & Resize(int sz, int x = 0) { // !!改度必须用这个改,不能手动改,别用错 Resize()
resize(sz, x), resize((deg = sz - 1) > 0 ? (1ll << 1 + __lg(deg)) : 1, x);
for (int i = Inv.size(); i <= size(); i++) {
Inv.emplace_back((mod - mod / i) * Inv[mod % i] % mod);
}
for (int bit = W[0].size(); 1ll << bit < size(); bit++) {
for (auto op : {0, 1}) {
W[op].emplace_back(::binpow(g[op], mod >> bit + 1, mod));
}
}
return *this;
} Poly(int sz = 1, int x = 0) {
Resize(sz, x);
} Poly(const Poly & f, int sz = 0, int x = 0) : vector(f), deg(f.deg) {
if (sz) Resize(sz, x); // 拷贝,有要改 sz 才改
} Poly(vector::iterator l, vector::iterator r, int sz = 0, int x = 0) : vector(l, r) {
Resize(sz ? sz : max<int>(1, size()), x); // 要注意传入的 size 为 0 的情况
} Poly(initializer_list<int> f) : vector(f) {
Resize(max<int>(1, size()));
}
void NTT(int op) { // 1 为 DFT, 0 为 IDFT
vector<int> Rev(size());
for (int i = 0; i < size(); i++) {
Rev[i] = ((i & 1) * size() | Rev[i >> 1]) >> 1;
if (i < Rev[i]) ::swap(at(i), at(Rev[i]));
}
for (int h = 1, t = 0; h < size(); h <<= 1, t++) {
for (int j = 0; j < size(); j += h << 1) {
for (int k = j, tw = 1; k < j + h; k++, (tw *= W[op][t]) %= mod) {
(at(k + h) = at(k) - tw * at(k + h) % mod + mod) %= mod;
(at(k) += at(k) - at(k + h) + mod) %= mod;
}
}
}
for (int i = 0; !op && i < size(); i++) {
(at(i) *= Inv[size()]) %= mod;
}
} Poly & operator *= (const Poly & t) {
Resize(deg + t.deg + 1);
Poly b(t, deg + 1);
NTT(1), b.NTT(1);
for (int i = 0; i < size(); i++) {
(at(i) *= b[i]) %= mod;
}
return NTT(0), *this;
} Poly operator * (const Poly & t) { return Poly(*this) *= t; }
Poly & operator *= (const int & k) {
for (int i = 0; i <= deg; i++) {
(at(i) *= k) %= mod;
}
return *this;
} Poly operator * (const int & k) { return Poly(*this) *= k; }
Poly & operator += (const Poly & t) {
Resize(max(deg, t.deg) + 1);
for (int i = 0; i <= t.deg; i++) {
(at(i) += t[i]) %= mod;
}
return *this;
} Poly operator + (const Poly & t) { return Poly(*this) += t; }
Poly & operator -= (const Poly & t) {
Resize(max(deg, t.deg) + 1);
for (int i = 0; i <= t.deg; i++) {
(at(i) += mod - t[i]) %= mod;
}
return *this;
} Poly operator - (const Poly & t) { return Poly(*this) -= t; }
Poly & operator /= (const Poly & t) {
return *this = DivMod(t)[0];
} Poly operator / (const Poly & t) { return DivMod(t)[0]; }
Poly & operator %= (const Poly & t) {
return *this = DivMod(t)[1];
} Poly operator % (const Poly & t) { return DivMod(t)[1]; }
Poly & operator >>= (const int & k) { // 消灭低次项
if (deg < k) return *this = Poly();
copy(begin() + k, begin() + deg + 1, begin());
return Resize(deg - k + 1);
} Poly operator >> (const int & k) { return Poly(*this) >>= k; }
Poly & operator <<= (const int & k) { // 增加低次项
insert(begin(), k, 0);
return Resize(deg + k + 1);
} Poly operator << (const int & k) { return Poly(*this) <<= k; }
Poly inv() { // 存在当且仅当 at(0) != 0 ,使用时用临时变量开至模 x^sz 大小
Poly f(1, binpow(at(0), mod - 2, mod)); // f 为逆
for (int bit = 2; bit >> 1 <= deg; bit <<= 1) { // h 为原函数
Poly h(begin(), begin() + bit, bit << 1); // 要开四倍空间
f.Resize(h.size()); // 俩个函数 (bit >> 1) 和 一个为 bit 相乘
f.NTT(1), h.NTT(1);
for (int i = 0; i < h.size(); i++) {
(f[i] *= 2 - f[i] * h[i] % mod + mod) %= mod;
}
f.NTT(0), f.Resize(bit);
}
return f.Resize(deg + 1); // 记得更改度
}
array<Poly, 2> DivMod(const Poly & b) {
if (deg < b.deg) return {Poly(), *this}; // 小于直接返回
Poly r(*this), q(b); // 要先取反再 Resize
reverse(r.begin(), r.begin() + r.deg + 1), reverse(q.begin(), q.begin() + q.deg + 1);
q = (q.Resize(deg - b.deg + 1).inv() * r).Resize(deg - b.deg + 1);
reverse(q.begin(), q.begin() + q.deg + 1);
return {q, (*this - q * b).Resize(b.deg)};
}
int GetDelta() { // at(0) == 0 的转化
return find_if(begin(), end(), [](auto & x) { return x != 0; }) - begin();
}
Poly EasySqrt(int delta = 0, int root0 = 1) { // 只用于 at(0) = 1,使用时用临时变量开至模 x^n 大小
Poly f(1, root0);
for (int bit = 2; (bit >> 1) + delta <= deg; bit <<= 1) {
Poly h(begin() + delta, begin() + bit + delta, bit << 1), invf = f.Resize(bit).inv();
f.Resize(h.size()), invf.Resize(h.size());
f.NTT(1), h.NTT(1), invf.NTT(1);
for (int i = 0; i < h.size(); i++) {
(f[i] = Inv[2] * (f[i] + h[i] * invf[i] % mod) % mod) %= mod;
}
f.NTT(0), f.Resize(bit);
}
return f.Resize(deg + 1); // 记得更改度
} vector<Poly> sqrt(int delta = 0, vector<Poly> res = {}) { // 考虑所以情况和所有解,size为 0 表示无解
if ((delta = GetDelta()) > deg) return {*this}; // 全 0
if (delta & 1) return {}; // 无解
auto root = Cipolla(at(delta), mod); // 求字典序最小可以拿出来只跑一次
for (auto & x : root) {
res.push_back(EasySqrt(delta, x));
}
return res;
}
Poly dev() { // 求导
Poly f(deg);
for (int i = 1; i <= deg; i++) {
(f[i - 1] = i * at(i)) %= mod;
}
return f;
} Poly indev() { // 积分
Poly f(deg + 2);
for (int i = 0; i <= deg; i++) {
(f[i + 1] = Inv[i + 1] * at(i)) %= mod;
}
return f;
}
Poly ln() { // 存在当且仅当 at(0) = 1
return (dev() * inv()).Resize(deg).indev();
} Poly exp() { // 存在当且仅当 at(0) = 0
Poly f(1, 1);
for (int bit = 2; bit >> 1 <= deg; bit <<= 1) {
Poly h(begin(), begin() + bit, bit << 1), lnf = f.Resize(bit).ln();
f.Resize(h.size()), lnf.Resize(h.size());
f.NTT(1), h.NTT(1), lnf.NTT(1);
for (int i = 0; i < h.size(); i++) {
(f[i] *= (1 - lnf[i] + mod + h[i])) %= mod;
}
f.NTT(0), f.Resize(bit);
}
return f.Resize(deg + 1);
}
Poly pow(string s, int delta = 0, int k0 = 0, int k1 = 0) { // 使用的时候 to_string
if ((delta = GetDelta()) > deg) return *this; // 全 0
for (auto & x : s) {
(k0 = k0 * 10 + (x - '0')) %= mod, (k1 = k1 * 10 + (x - '0')) %= mod - 1;
if (delta * k1 > deg) return Poly(deg + 1); // mod x^sz 后为 0
}
auto f = ((*this) >> delta).Resize(deg - delta * k1 + 1) * binpow(at(delta), mod - 2, mod);
return (f.ln() * k0).exp() * binpow(at(delta), k1, mod) << delta * k1;
}
// 使用的点都要互不相同
static Poly & DivFFT(iterator l, iterator r, vector<Poly> & tr, int op = 1, int p = 1) { // 求横坐标轴上插值, op = 1 正常,op = 0 求转置
if (next(l) == r) return op ? tr[p] = {mod - *l, 1} : tr[p] = {1, mod - *l}; // 左闭右开
auto mid = next(l, r - l + 1 >> 1);
return tr[p] = DivFFT(l, mid, tr, op, p << 1) * DivFFT(mid, r, tr, op, p << 1 | 1);
}
Poly T_Mul(Poly & b, Poly c = {}) { // 辅助函数,转置乘法,会修改 b
reverse(b.begin(), b.begin() + b.deg + 1), c = *this * b;
return Poly(c.begin() + b.deg, c.begin() + c.deg + 1);
}
vector MultiPoint(iterator L, iterator R, vector<int> res = {}) { // 多点求值,左闭右开
vector<Poly> tr(max<int>(deg + 1, R - L) << 2); // 传入 n 个点,返回 n 个对应点
Poly x(L, R, max<int>(deg + 1, R - L));
auto Find = [&](auto && self, auto l, auto r, int p = 1) { // 求值过程
if (next(l) == r) return res.push_back(tr[p][0]);
auto mid = next(l, r - l + 1 >> 1);
tr[p].Resize(r - l + 1);
tie(tr[p << 1], tr[p << 1 | 1]) = pair{tr[p].T_Mul(tr[p << 1 | 1]), tr[p].T_Mul(tr[p << 1])};
self(self, l, mid, p << 1), self(self, mid, r, p << 1 | 1);
};
tr[1] = T_Mul(tr[1] = DivFFT(x.begin(), x.begin() + x.deg + 1, tr, 0).inv());
return Find(Find, x.begin(), x.begin() + x.deg + 1), res.resize(R - L), res;
}
static Poly QuickPolate(vector<array<int, 2>>::iterator L, vector<array<int, 2>>::iterator R) {
vector<Poly> tr(R - L << 2); // 快速插值,给二维点求函数,左闭右开
Poly x(R - L);
for (auto i = L; i != R; i++) {
x[i - L] = i -> at(0);
}
auto ty = DivFFT(x.begin(), x.begin() + x.deg + 1, tr, 1).dev().MultiPoint(x.begin(), x.begin() + x.deg + 1);
auto Find = [&](auto && self, auto l, auto r, int p = 1) { // 求值过程
if (next(l) == r) return Poly(1, l -> at(1) * binpow(ty[l - L], mod - 2, mod) % mod);
auto mid = next(l, r - l + 1 >> 1);
return self(self, l, mid, p << 1) * tr[p << 1 | 1] + self(self, mid, r, p << 1 | 1) * tr[p << 1];
};
return Find(Find, L, R);
}
};
template <int mod, const int* G>
vector<int> Poly<mod, G>::Inv(2, 1);
template <int mod, const int* G>
array<vector<int>, 2> Poly<mod, G>::W;
vector<int> inv, fact, invfact;
struct Combine {
Combine(int n) {
inv = fact = invfact = vector<int>(n + 1, 1);
for (int i = 2; i <= n; i++) {
(inv[i] = (mod - mod / i) * inv[mod % i]) %= mod, (fact[i] = fact[i - 1] * i) %= mod, (invfact[i] = invfact[i - 1] * inv[i]) %= mod;
}
}
int operator()(int n, int m) { return m > n || n < 0 || m < 0 ? 0 : fact[n] * invfact[m] % mod * invfact[n - m] % mod; }
int P(int n, int m) { return m > n || n < 0 || m < 0 ? 0 : fact[n] * invfact[n - m] % mod; }
int Lucas(int n, int m) { return m == 0 ? 1 : (*this)(n % mod, m % mod) * Lucas(n / mod, m / mod) % mod; }
} C(200);
void QAQ() {
int n, k;
cin >> n >> k;
vector<int> a(n), b(n);
for (int i = 0; i < n; cin >> a[i++]);
for (int i = 0; i < n; cin >> b[i++]);
auto F = [&](auto && self, vector<int> & a, vector<int> & b, int now) -> Poly<> {
if (a.size() == 0 || b.size() == 0) return {1};
auto get = [&](int a, int b) {
Poly t(min(a, b) + 1);
for (int i = 0; i <= t.deg; i++) {
t[i] = C.P(a, i) * C(b, i) % mod;
}
return t;
};
if (now == -1) return get(a.size(), b.size());
vector<int> a0, a1, b0, b1;
for (auto & x : a) {
if (x >> now & 1) a1.push_back(x ^ (1ll << now));
else a0.push_back(x);
}
for (auto & x : b) {
if (x >> now & 1) b1.push_back(x ^ (1ll << now));
else b0.push_back(x);
}
if (k >> now & 1) {
auto t1 = self(self, a0, b1, now - 1), t2 = self(self, a1, b0, now - 1);
auto t = t1 * t2;
t.Resize(min(a.size(), b.size()) + 1);
return t;
} else {
auto t1 = self(self, a0, b0, now - 1), t2 = self(self, a1, b1, now - 1);
Poly t(min(a.size(), b.size()) + 1);
for (int i = 0; i <= t1.deg; i++) {
for (int j = 0; j <= t2.deg; j++) {
auto tmp = get(a0.size() - i, b1.size() - j) * get(a1.size() - j, b0.size() - i);
for (int k = 0; k <= tmp.deg; k++) {
(t[i + j + k] += t1[i] * t2[j] % mod * tmp[k]) %= mod;
}
}
}
return t;
}
};
auto res = F(F, a, b, 61);
int ans = 0;
for (int i = 1; i <= res.deg; i++) {
cout << res[i] << "\n";
}
}
signed main() {
cin.tie(0) -> sync_with_stdio(0);
int t = 1;
// cin >> t;
while (t--) {
QAQ();
}
}
这程序好像有点Bug,我给组数据试试?
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 1ms
memory: 3720kb
input:
9 5 1 7 2 8 4 9 2 5 10 1 3 2 4 5 8 8 8 9
output:
51 1034 10768 62195 200965 348924 294444 97344 7200
result:
ok 9 lines
Test #2:
score: 0
Accepted
time: 67ms
memory: 3828kb
input:
200 569102225177443347 1103663383682482176 1103381908705771520 1099441259031822336 1098878309078401024 1089871109823660032 1080863910568919040 1074108511127863296 1071856711314178048 1069041961547071488 1068479011593650176 1067353111686807552 1062849512059437056 1049338713177325568 10448351135499550...
output:
20506 208107723 47878304 53020813 972282728 933586852 658157196 670189811 957980024 366179738 217980591 967482558 833450149 987731802 260904367 5263881 600332344 906061351 658256294 93700706 421323952 178075016 219871690 986880524 848776106 191185484 641917326 576497440 908609746 349728876 606714342...
result:
ok 200 lines
Test #3:
score: 0
Accepted
time: 11ms
memory: 3736kb
input:
200 1098723432450995412 972777519512027136 936748722493063168 864691128455135232 860187528827764736 857935729014079488 856246879153815552 855683929200394240 851180329573023744 848928529759338496 847802629852495872 847310048643252224 847239679899074560 846676729945653248 828662331436171264 8280993814...
output:
8320 34035512 428014253 916072411 696504298 748377440 32424677 188402417 233587075 130639672 759476380 546285625 187068736 159002787 131866334 381530906 133126344 373727612 923311054 725293681 718162548 39511135 322320638 44709653 156884882 285926751 787179409 282967016 153092344 615721347 950855850...
result:
ok 200 lines
Test #4:
score: 0
Accepted
time: 3ms
memory: 4200kb
input:
200 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
output:
3072 4412928 940025853 665370743 752672705 581549490 41990996 541401698 170451802 26584141 220983766 844620126 64506869 137621326 418866920 351049174 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
result:
ok 200 lines
Test #5:
score: 0
Accepted
time: 4ms
memory: 3992kb
input:
200 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...
output:
40000 792020000 319908096 286630939 515085548 95626140 472749362 800008042 594973486 139901984 847967250 125664877 254232250 419486325 204481923 979660340 41873095 540955890 585129047 205968776 196086667 674391130 737319172 669580034 973843015 207125612 331414909 119844754 24879477 990932807 8476927...
result:
ok 200 lines
Extra Test:
score: 0
Extra Test Passed