从这里开始
好像那天正好在路上,成功错过了打(掉)比赛(rating)的好机会。
(据可靠消息称,神仙 jerome_wei 不走水就捧杯了。
因为我不太会二次剩余,所以现在还没补 E。
Problem A 新年的促销
dp 即可。
不难注意到假设最终一共带走了 $k$ 袋大米,那么购买的一定是其中价格最小的若干袋。
考虑枚举买走的大米的最大价值,记录一下买了多少袋,以及花了多少钱,然后就计算答案了。
时间复杂度 $O(n^2m)$
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; #define ll long long const int N = 305, M = 1e3 + 5; const ll llf = (signed ll) (~0ull >> 3); typedef class Item { public: int w, p; } Item; int n, m, a, b; Item it[N]; ll ans[M]; ll f[N][M]; int main() { scanf("%d%d%d%d", &n, &m, &a, &b); for (int i = 1; i <= n; i++) { scanf("%d", &it[i].w); } for (int i = 1; i <= n; i++) { scanf("%d", &it[i].p); } sort(it + 1, it + n + 1, [&] (const Item& a, const Item& b) { return a.w > b.w; }); for (int i = 0; i <= m; i++) ans[i] = -llf; for (int i = 0; i <= n; i++) for (int j = 0; j <= m; j++) f[i][j] = -llf; f[0][0] = 0; for (int i = 1; i <= n; i++) { int id = i; for (int j = i + 1; j <= n; j++) if (it[j].p < it[id].p) id = j; rotate(it + i, it + id, it + id + 1); for (int j = i; j; j--) { for (int k = m; k >= it[i].p; k--) { f[j][k] = max(f[j][k], f[j - 1][k - it[i].p] + it[i].w); } } ll sum = 0; int cnt = 0; for (int j = 1; j <= i; j++) { int x = (j / a) + (j / b); while (i + cnt < n && cnt < x) sum += it[i + ++cnt].w; for (int k = 1; k <= m; k++) { ans[k] = max(ans[k], sum + f[j][k]); } } } ans[0] = 0; for (int i = 1; i <= m; i++) { ans[i] = max(ans[i], ans[i - 1]); printf("%lld ", ans[i]); } return 0; }
Problem B 新年的新航线
可以猜想 $n > 3$ 一定有解。
考虑度为 $2$ 的点 $p$,与它相邻的点是 $u, v$,那么它在生成树上的度数只可能为 1。那么相当于会对 $u, v$ 中其中一个点的度数加上 1。因为是三角剖分,所以一定存在边 $(u, v)$,我们给 $(u, v)$ 标上数 $i$。
所以现在的问题是给一个边界上有标数的多边形找一个生成树,满足每个点的度数要么为 1,要么至少为 3。简单讨论一下可以发现 $n = 4$ 始终有解。考虑不断减少一个 $n > 4$ 的多边形的点数。
仍然考虑 2 度点 $p$,考虑仍然硬点它和其他在多边形上的点恰好有 1 条边。不妨设和它相邻的点是 $u, v$。
- 如果 $(p, u), (p, v)$ 无标数,那么给 $(u, v)$ 标上数 $p$,然后删掉 $p$。
- 如果 $(p, u)$ 有标数 $s$,$(p, v)$ 无标数,那么连上边 $(s, u), (p, u)$,然后删掉 $p$
- 如果 $(p, u), (p, v)$ 有标数,那么它们标数均向 $p$ 连边,然后给 $(u, v)$ 标上 $p$,再删掉 $p$
不难做到线性。
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; const int N = 1e6 + 5, N2 = N << 1; #define pii pair<int, int> int n; int d[N]; boolean ban[N2]; int us[N2], vs[N2]; vector<int> G[N]; vector<pii> lab[N]; vector<pii> ans; int main() { scanf("%d", &n); if (n == 3) { puts("-1"); return 0; } int ce = 0; for (int i = 1; i <= n; i++) { int u = i; int v = (i == n) ? (1) : (i + 1); ++ce; d[u]++, d[v]++; us[ce] = u, vs[ce] = v; G[u].push_back(i); G[v].push_back(i); } for (int i = 1, u, v; i <= n - 3; i++) { scanf("%d%d", &u, &v); ++ce; us[ce] = u, vs[ce] = v; G[u].push_back(ce); G[v].push_back(ce); d[u]++, d[v]++; } queue<int> Q; for (int i = 1; i <= n; i++) { if (d[i] == 2) { Q.push(i); } } for (int _ = 1; _ <= n - 4; _++) { int p = Q.front(); Q.pop(); vector<int> tmp; for (auto eid : G[p]) { if (!ban[eid]) { tmp.push_back(eid); } } G[p].clear(); assert(tmp.size() == 2u); int ex = tmp[0], ey = tmp[1]; int u = us[ex] ^ vs[ex] ^ p; int v = us[ey] ^ vs[ey] ^ p; int lx = 0, ly = 0; for (auto par : lab[p]) { int e = par.first; int w = par.second; if (e == u) { lx = w; } else if (e == v) { ly = w; } } ban[ex] = ban[ey] = true; lab[p].clear(); if (lx && ly) { ans.emplace_back(lx, p); ans.emplace_back(ly, p); lab[u].emplace_back(v, p); lab[v].emplace_back(u, p); } else if (!lx && !ly) { lab[u].emplace_back(v, p); lab[v].emplace_back(u, p); } else if (lx && !ly) { ans.emplace_back(lx, u); ans.emplace_back(p, u); } else { ans.emplace_back(ly, v); ans.emplace_back(p, v); } if (--d[u] == 2) Q.push(u); if (--d[v] == 2) Q.push(v); } vector<int> rest; for (int i = 1; i <= n; i++) { if (!G[i].empty()) { rest.push_back(i); } } sort(rest.begin(), rest.end(), [&] (int x, int y) { return d[x] > d[y]; }); assert(rest.size() == 4u); auto have_nearby = [&] (int x) { for (auto y : lab[x]) { int e = y.first; if (!G[e].empty()) { return true; } } return false; }; auto link_nearby = [&] (int p) { for (auto y : lab[p]) { int e = y.first; if (G[e].empty()) continue; int q = y.second; ans.emplace_back(p, q); } }; boolean flag0 = have_nearby(rest[0]); boolean flag1 = have_nearby(rest[1]); if (flag0 && flag1) { link_nearby(rest[0]); link_nearby(rest[1]); ans.emplace_back(rest[0], rest[1]); ans.emplace_back(rest[2], rest[0]); ans.emplace_back(rest[3], rest[1]); } else if (flag0) { link_nearby(rest[0]); ans.emplace_back(rest[0], rest[1]); ans.emplace_back(rest[0], rest[2]); ans.emplace_back(rest[0], rest[3]); } else { link_nearby(rest[1]); ans.emplace_back(rest[1], rest[0]); ans.emplace_back(rest[1], rest[2]); ans.emplace_back(rest[1], rest[3]); } assert((signed) ans.size() == n - 1); for (auto par : ans) { printf("%d %d ", par.first, par.second); } return 0; }
Problem C 新年的复读机
相信三方的区间 dp 大家都会。
如果 $n = 1$ 的时候答案为 0。
如果 $n > 1$ ,每个数一定会对答案有贡献,考虑原来的数合并的时候不会新产生贡献。考虑合并 gcd 为 $g_1$ 和 $g_2$ 的两段,它们的长度都至少为 2,两段的长度分别为 $l_1, l_2$,不妨设 $g_1 leqslant g_2$,那么至少会额外花费 $g_1 + g_2 (l_2 - 1)$ 的代价,而考虑不断将第二段中的数依次加入第一段中,至多会花费 $g_1 l_2$ 的代价。
因此存在一种最优策略是从一个点开始,每次不断将左侧或者右侧的点加进来。
不难发现向一边拓展的时候一定会拓展到 gcd 发生变化为止,否则做一些简单调整可以让答案更优。
然后粗略分析得到了状态数为 $O(nlog^2 V)$ 的 dp 做法。
冷静一下仔细分析发现,每个状态 $[l, r]$ 一定满足要么 $l = 1$ 或者 $r = n$,要么 $r$ 是从 $l$ 开始的前缀 gcd 发生变化的位置,要么 $l$ 是从 $r$ 开始的后缀 gcd 发生变化的位置。因此状态数为 $O(nlog V)$。
经过一些简单预处理能够让转移做到 $O(1)$。
常数太大,卡不过去,sad.....
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; const int N = 2e5 + 5, M = 21000000; #define ll long long #define pil pair<int, ll> #define pii pair<int, int> const ll llf = (signed ll) (~0ull >> 2); template <typename T> T gcd(T a, T b) { return (!b) ? a : gcd(b, a % b); } template <typename T> void vmin(T& a, T b) { (a > b) && (a = b); } typedef class Status { public: int l, r; ll v, f; Status *chl, *chr; Status() { } Status(int l, int r, ll v) : l(l), r(r), v(v), f(llf) { } void update() { (chl) && (vmin(chl->f, f + (l - chl->l) * v), 0); (chr) && (vmin(chr->f, f + (chr->r - r) * v), 0); } } Status; int n; ll a[N]; Status pl[M], *top = pl; vector<Status*> pre[N], suf[N]; Status* get(int l, int r, ll v) { return *top = Status(l, r, v), top++; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%lld", a + i); } for (int i = 1; i <= n; i++) { pre[i].push_back(get(i, i, a[i])); ll v = a[i]; for (auto it = pre[i - 1].rbegin(); it != pre[i - 1].rend(); it++) { int pos = (*it)->l; v = gcd((*it)->v, v); if (v ^ pre[i].back()->v) pre[i].push_back(get(pos, i, v)); } if (pre[i].back()->l != 1) pre[i].push_back(get(1, i, v)); reverse(pre[i].begin(), pre[i].end()); Status *tmp = NULL; for (auto x : pre[i]) x->chl = tmp, tmp = x; } for (int i = n; i; i--) { suf[i].emplace_back(pre[i].back()); ll v = a[i]; for (auto it : suf[i + 1]) { int pos = it->r; v = gcd(v, it->v); if (v != suf[i].back()->v) suf[i].push_back(get(i, pos, v)); } if (suf[i].back()->r != n) suf[i].push_back(get(i, n, v)); Status* tmp = NULL; for (auto it = suf[i].rbegin(); it != suf[i].rend(); it++) (*it)->chr = tmp, tmp = *it; } assert(top - pl < M); vector<int> h (n + 1, -1); vector<Status*> G; vector<int> nxt; for (int i = n; i; i--) { for (auto x : pre[i]) { G.push_back(x); nxt.push_back(h[x->l]); h[x->l] = (signed) G.size() - 1; } } for (int i = 1; i <= n; i++) { auto it = suf[i].begin(); auto _it = suf[i].end(); for (int _ = h[i]; ~_; _ = nxt[_]) { auto& t = G[_]; while (it != _it && (*it)->r <= t->r) it++; t->chr = (it == _it) ? (NULL) : (*it); } h[i] = -1; } G.clear(), nxt.clear(); for (int i = n; i; i--) { for (auto x : suf[i]) { G.push_back(x); nxt.push_back(h[x->r]); h[x->r] = (signed) G.size() - 1; } } for (int i = 1; i <= n; i++) { auto st = pre[i].begin(), it = st; auto _it = pre[i].end(); for (int _ = h[i]; ~_; _ = nxt[_]) { auto& t = G[_]; while (it != _it && (*it)->l < t->l) it++; t->chl = (it == st) ? (NULL) : (*(it - 1)); } h[i] = -1; } G.clear(), nxt.clear(); for (Status* p = pl; p != top; p++) { int len = p->r - p->l; G.push_back(p); nxt.push_back(h[len]); h[len] = (signed) G.size() - 1; } for (int _ = h[0]; ~_; _ = nxt[_]) { auto& x = G[_]; x->f = -x->v; } for (int i = 0; i < n - 1; i++) { for (int _ = h[i]; ~_; _ = nxt[_]) { G[_]->update(); } } ll ans = llf; for (int _ = h[n - 1]; ~_; _ = nxt[_]) { ans = min(ans, G[_]->f); } for (int i = 1; i <= n; i++) ans += a[i]; printf("%lld ", ans); return 0; }
Problem D 新年的追逐战
不难注意到 $H$ 的连通块在 $G_i$ 是上是连通的。
考虑每个 $G_i$ 选一个连通块出来,那么在 $H$ 中会形成多少个连通块
- 如果存在一个连通块大小为 1,那么在 $H$ 中这些都是孤立点
- 如果其中有 $k$ 个是二分图,那么会有 $2^{max{k - 1, 0}}$ 个连通块。证明的话,考虑对其中的二分图进行黑白染色,如果确定了其中一个图是在黑点还是在白点,剩下的二分图中是在黑点还是白点是确定的,充分性的话可以简单归纳一下。
相信数 $n$ 个点的带标号连通二分图大家都会。
剩下是个简单 dp。
#include <bits/stdc++.h> using namespace std; typedef bool boolean; #define ll long long template <typename T> void pfill(T* pst, const T* ped, T val) { for ( ; pst != ped; *(pst++) = val); } template <typename T> void pcopy(T* pst, const T* ped, T* pval) { for ( ; pst != ped; *(pst++) = *(pval++)); } const int N = 262144; const int Mod = 998244353; const int bzmax = 19; const int g = 3; void exgcd(int a, int b, int& x, int& y) { if (!b) { x = 1, y = 0; } else { exgcd(b, a % b, y, x); y -= (a / b) * x; } } int inv(int a, int Mod) { int x, y; exgcd(a, Mod, x, y); return (x < 0) ? (x + Mod) : (x); } template <const int Mod = :: Mod> class Z { public: int v; Z() : v(0) { } Z(int x) : v(x){ } Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) { int x; return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x)); } friend Z operator - (const Z& a, const Z& b) { int x; return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x)); } friend Z operator * (const Z& a, const Z& b) { return Z(a.v * 1ll * b.v); } friend Z operator ~ (const Z& a) { return inv(a.v, Mod); } friend Z operator - (const Z& a) { return Z(0) - a; } Z& operator += (Z b) { return *this = *this + b; } Z& operator -= (Z b) { return *this = *this - b; } Z& operator *= (Z b) { return *this = *this * b; } friend boolean operator == (const Z& a, const Z& b) { return a.v == b.v; } }; typedef Z<> Zi; Zi qpow(Zi a, int p) { if (p < Mod - 1) p += Mod - 1; Zi rt = 1, pa = a; for ( ; p; p >>= 1, pa = pa * pa) { if (p & 1) { rt = rt * pa; } } return rt; } const Zi inv2 ((Mod + 1) >> 1); class NTT { private: Zi gn[bzmax + 4], _gn[bzmax + 4]; public: NTT() { for (int i = 0; i <= bzmax; i++) { gn[i] = qpow(Zi(g), (Mod - 1) >> i); _gn[i] = qpow(Zi(g), -((Mod - 1) >> i)); } } void operator () (Zi* f, int len, int sgn) { for (int i = 1, j = len >> 1, k; i < len - 1; i++, j += k) { if (i < j) swap(f[i], f[j]); for (k = len >> 1; k <= j; j -= k, k >>= 1); } Zi *wn = (sgn > 0) ? (gn + 1) : (_gn + 1), w, a, b; for (int l = 2, hl; l <= len; l <<= 1, wn++) { hl = l >> 1, w = 1; for (int i = 0; i < len; i += l, w = 1) { for (int j = 0; j < hl; j++, w *= *wn) { a = f[i + j], b = f[i + j + hl] * w; f[i + j] = a + b; f[i + j + hl] = a - b; } } } if (sgn < 0) { Zi invlen = ~Zi(len); for (int i = 0; i < len; i++) { f[i] *= invlen; } } } int correct_len(int len) { int m = 1; for ( ; m <= len; m <<= 1); return m; } } NTT; void pol_inverse(Zi* f, Zi* g, int n) { static Zi A[N]; if (n == 1) { g[0] = ~f[0]; } else { int hn = (n + 1) >> 1, t = NTT.correct_len(n << 1 | 1); pol_inverse(f, g, hn); pcopy(A, A + n, f); pfill(A + n, A + t, Zi(0)); pfill(g + hn, g + t, Zi(0)); NTT(A, t, 1); NTT(g, t, 1); for (int i = 0; i < t; i++) { g[i] = g[i] * (Zi(2) - g[i] * A[i]); } NTT(g, t, -1); pfill(g + n, g + t, Zi(0)); } } void pol_sqrt(Zi* f, Zi* g, int n) { static Zi A[N], B[N]; if (n == 1) { g[0] = f[0]; } else { int hn = (n + 1) >> 1, t = NTT.correct_len(n + n); pol_sqrt(f, g, hn); pfill(g + hn, g + n, Zi(0)); for (int i = 0; i < hn; i++) A[i] = g[i] + g[i]; pfill(A + hn, A + t, Zi(0)); pol_inverse(A, B, n); pcopy(A, A + n, f); pfill(A + n, A + t, Zi(0)); NTT(A, t, 1); NTT(B, t, 1); for (int i = 0; i < t; i++) A[i] *= B[i]; NTT(A, t, -1); for (int i = 0; i < n; i++) g[i] = g[i] * inv2 + A[i]; } } typedef class Poly : public vector<Zi> { public: using vector<Zi>::vector; Poly& fix(int sz) { resize(sz); return *this; } } Poly; Poly operator + (Poly A, Poly B) { int n = A.size(), m = B.size(); int t = max(n, m); A.resize(t), B.resize(t); for (int i = 0; i < t; i++) { A[i] += B[i]; } return A; } Poly operator - (Poly A, Poly B) { int n = A.size(), m = B.size(); int t = max(n, m); A.resize(t), B.resize(t); for (int i = 0; i < t; i++) { A[i] -= B[i]; } return A; } Poly sqrt(Poly a) { Poly rt (a.size()); pol_sqrt(a.data(), rt.data(), a.size()); return rt; } Poly operator * (Poly A, Poly B) { int n = A.size(), m = B.size(); int k = NTT.correct_len(n + m - 1); if (n < 20 || m < 20) { Poly rt (n + m - 1); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { rt[i + j] += A[i] * B[j]; } } return rt; } A.resize(k), B.resize(k); NTT(A.data(), k, 1); NTT(B.data(), k, 1); for (int i = 0; i < k; i++) { A[i] *= B[i]; } NTT(A.data(), k, -1); A.resize(n + m - 1); return A; } Poly operator ~ (Poly f) { int n = f.size(), t = NTT.correct_len((n << 1) | 1); Poly rt (t); f.resize(t); pol_inverse(f.data(), rt.data(), n); rt.resize(n); return rt; } Poly operator / (Poly A, Poly B) { int n = A.size(), m = B.size(); if (n < m) { return Poly {0}; } int r = n - m + 1; reverse(A.begin(), A.end()); reverse(B.begin(), B.end()); A.resize(r), B.resize(r); A = A * ~B; A.resize(r); reverse(A.begin(), A.end()); return A; } Poly operator % (Poly A, Poly B) { int n = A.size(), m = B.size(); if (n < m) { return A; } if (m == 1) { return Poly {0}; } A = A - A / B * B; A.resize(m - 1); return A; } Zi Inv[N]; void init_inv(int n) { Inv[0] = 0, Inv[1] = 1; for (int i = 2; i <= n; i++) { Inv[i] = Inv[Mod % i] * Zi((Mod - (Mod / i))); } } void diff(Poly& f) { if (f.size() == 1) { f[0] = 0; return; } for (int i = 1; i < (signed) f.size(); i++) { f[i - 1] = f[i] * Zi(i); } f.resize(f.size() - 1); } void integ(Poly& f) { f.resize(f.size() + 1); for (int i = (signed) f.size() - 1; i; i--) { f[i] = f[i - 1] * Inv[i]; } f[0] = 0; } Poly ln(Poly f) { int n = f.size(); Poly h = f; diff(h); f = h * ~f; f.resize(n - 1); integ(f); return f; } void pol_exp(Poly& f, Poly& g, int n) { Poly h; if (n == 1) { g.resize(1); g[0] = 1; } else { int hn = (n + 1) >> 1; pol_exp(f, g, hn); h.resize(n), g.resize(n); pcopy(h.data(), h.data() + n, f.data()); g = g * (Poly{1} - ln(g) + h); g.resize(n); } } Poly exp(Poly f) { int n = f.size(); Poly rt; pol_exp(f, rt, n); return rt; } class PolyBuilder { protected: int num; Poly P[N << 1]; void _init(int *x, int l, int r) { if (l == r) { P[num++] = Poly{-Zi(x[l]), Zi(1)}; return; } int mid = (l + r) >> 1; int curid = num++; _init(x, l, mid); int rid = num; _init(x, mid + 1, r); P[curid] = P[curid + 1] * P[rid]; } void _evalute(Poly f, Zi* y, int l, int r) { f = f % P[num++]; if (l == r) { y[l] = f[0]; return; } int mid = (l + r) >> 1; _evalute(f, y, l, mid); _evalute(f, y, mid + 1, r); } public: Poly evalute(Poly f, int* x, int n) { Poly rt(n); num = 0; _init(x, 0, n - 1); num = 0; _evalute(f, rt.data(), 0, n - 1); return rt; } } PolyBuilder; int n, m; int sz[N]; Zi fac[N], _fac[N]; void prepare(int n) { fac[0] = 1; for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i; _fac[n] = ~fac[n]; for (int i = n; i; i--) _fac[i - 1] = _fac[i] * i; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", sz + i); m = max(m, sz[i]); } prepare(m); init_inv(m); Zi inv2 ((Mod + 1) >> 1); Poly A (m + 1); for (int i = 0; i <= m; i++) { A[i] = qpow(inv2, 1ll * i * (i - 1) / 2 % (Mod - 1)) * _fac[i]; } Poly biG = (A * A).fix(m + 1); for (int i = 0; i <= m; i++) { biG[i] = biG[i] * qpow(2, 1ll * i * (i - 1) / 2 % (Mod - 1)); } Poly biF = ln(biG) * Poly {inv2}; Poly cmG (m + 1); for (int i = 0; i <= m; i++) cmG[i] = qpow(2, 1ll * i * (i - 1) / 2 % (Mod - 1)) * _fac[i]; Poly cmF = ln(cmG); Poly cmFn = cmF; for (int i = 0; i <= m; i++) cmFn[i] *= i; for (int i = 0; i <= m; i++) A[i] = _fac[i] * qpow(2, 1ll * i * (i - 1) / 2 % (Mod - 1)); biF[1] = cmF[1] = 0; Poly biH = (biF * A).fix(m + 1); Poly cmH = (cmF * A).fix(m + 1); Poly cmHn = (cmFn * A).fix(m + 1); for (int i = 0; i <= m; i++) { biH[i] *= fac[i]; cmH[i] *= fac[i]; cmHn[i] *= fac[i]; } Zi f[2] = {1, 0}, g[2] = {1, 0}; for (int i = 1; i <= n; i++) { int s = sz[i]; f[1] = f[1] * (biH[s] + cmH[s]) + f[0] * biH[s]; f[0] = f[0] * (cmH[s] - biH[s]); Zi coef = s * qpow(2, 1ll * (s - 1) * (s - 2) / 2 % (Mod - 1)); g[1] = g[1] * cmHn[s] + g[0] * coef; g[0] = g[0] * (cmHn[s] - coef); } Zi ans = f[1] + f[0] + g[1]; printf("%d ", ans.v); return 0; }
Problem E 新年的邀请函
咕咕咕
Problem D(old) 新年的求值
考虑这样一个问题 $q_i = a^i$。
那么它的答案等于 $f(q_i) = sum_{j = 0}^n f_j a^{ij}$
注意到 $ij = inom{i + j}{2} - inom{i}{2} - inom{j}{2}$。所以可以做一次减法卷积。
原问题的话就用一些简单换元法可以把问题规约成上面。
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; #define ll long long template <typename T> void pfill(T* pst, const T* ped, T val) { for ( ; pst != ped; *(pst++) = val); } template <typename T> void pcopy(T* pst, const T* ped, T* pval) { for ( ; pst != ped; *(pst++) = *(pval++)); } const int N = 1 << 21; const int Mod = 998244353; const int bzmax = 23; const int g = 3; void exgcd(int a, int b, int& x, int& y) { if (!b) { x = 1, y = 0; } else { exgcd(b, a % b, y, x); y -= (a / b) * x; } } int inv(int a, int Mod) { int x, y; exgcd(a, Mod, x, y); return (x < 0) ? (x + Mod) : (x); } template <const int Mod = :: Mod> class Z { public: int v; Z() : v(0) { } Z(int x) : v(x){ } Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) { int x; return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x)); } friend Z operator - (const Z& a, const Z& b) { int x; return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x)); } friend Z operator * (const Z& a, const Z& b) { return Z(a.v * 1ll * b.v); } friend Z operator ~ (const Z& a) { return inv(a.v, Mod); } friend Z operator - (const Z& a) { return Z(0) - a; } Z& operator += (Z b) { return *this = *this + b; } Z& operator -= (Z b) { return *this = *this - b; } Z& operator *= (Z b) { return *this = *this * b; } friend boolean operator == (const Z& a, const Z& b) { return a.v == b.v; } }; typedef Z<> Zi; Zi qpow(Zi a, int p) { if (p < Mod - 1) p += Mod - 1; Zi rt = 1, pa = a; for ( ; p; p >>= 1, pa = pa * pa) { if (p & 1) { rt = rt * pa; } } return rt; } const Zi inv2 ((Mod + 1) >> 1); class NTT { private: Zi gn[bzmax + 4], _gn[bzmax + 4]; public: NTT() { for (int i = 0; i <= bzmax; i++) { gn[i] = qpow(Zi(g), (Mod - 1) >> i); _gn[i] = qpow(Zi(g), -((Mod - 1) >> i)); } } void operator () (Zi* f, int len, int sgn) { for (int i = 1, j = len >> 1, k; i < len - 1; i++, j += k) { if (i < j) swap(f[i], f[j]); for (k = len >> 1; k <= j; j -= k, k >>= 1); } Zi *wn = (sgn > 0) ? (gn + 1) : (_gn + 1), w, a, b; for (int l = 2, hl; l <= len; l <<= 1, wn++) { hl = l >> 1, w = 1; for (int i = 0; i < len; i += l, w = 1) { for (int j = 0; j < hl; j++, w *= *wn) { a = f[i + j], b = f[i + j + hl] * w; f[i + j] = a + b; f[i + j + hl] = a - b; } } } if (sgn < 0) { Zi invlen = ~Zi(len); for (int i = 0; i < len; i++) { f[i] *= invlen; } } } int correct_len(int len) { int m = 1; for ( ; m <= len; m <<= 1); return m; } } NTT; typedef class Poly : public vector<Zi> { public: using vector<Zi>::vector; Poly& fix(int sz) { resize(sz); return *this; } } Poly; Poly operator * (Poly A, Poly B) { int n = A.size(), m = B.size(); int k = NTT.correct_len(n + m - 1); if (n < 20 || m < 20) { Poly rt (n + m - 1); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { rt[i + j] += A[i] * B[j]; } } return rt; } A.resize(k), B.resize(k); NTT(A.data(), k, 1); NTT(B.data(), k, 1); for (int i = 0; i < k; i++) { A[i] *= B[i]; } NTT(A.data(), k, -1); A.resize(n + m - 1); return A; } Zi fac[N], _fac[N]; void prepare(int n) { fac[0] = 1; for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i; _fac[n] = ~fac[n]; for (int i = n; i; i--) _fac[i - 1] = _fac[i] * i; } // f'(x) = f(x * d) void mul(Poly& a, Zi x) { Zi pw = 1; for (auto& y : a) y *= pw, pw *= x; } // f'(x) = f(x + d) Poly poly_mov(Poly f, Zi d) { int n = f.size(); Poly A (n); for (int i = 0; i < n; i++) f[i] *= fac[i]; Zi pw = 1; for (int i = 0; i < n; i++, pw = pw * d) A[i] = _fac[i] * pw; reverse(A.begin(), A.end()); f = f * A; for (int i = 0; i < n; i++) f[i] = f[i + n - 1] * _fac[i]; f.resize(n); return f; } int n, Q; Poly f; Zi q0, a, b; int main() { scanf("%d%d", &n, &Q); f.resize(++n); for (int i = 0; i < n; i++) { scanf("%d", &f[i].v); } scanf("%d%d%d", &q0.v, &a.v, &b.v); prepare(n + 1); mul(f, ~Zi(a - 1)); f = poly_mov(f, -b); mul(f, q0 * (a - 1) + b); ++Q; Poly A (n + Q - 1); A[0] = 1; Zi pw = 1; for (int i = 1; i < (signed) A.size(); i++) { A[i] = A[i - 1] * pw; pw *= a; } pw = 1; Zi _a = ~a, pwa = 1; for (int i = 1; i < n; i++) f[i] *= pwa, pwa *= (pw *= _a); reverse(f.begin(), f.end()); A = A * f; unsigned ans = 0; pw = pwa = 1; for (int i = 1; i < Q; i++) { Zi tmp = A[i + n - 1] * pwa; pwa *= (pw *= _a); ans ^= tmp.v; } printf("%u ", ans); return 0; }