@qq290637843
2020-12-01T22:33:49.000000Z
字数 29281
阅读 400
简单题
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul base = 998244353;ul plus(ul a, ul b){return a + b < base ? a + b : a + b - base;}ul mul(ul a, ul b){return ull(a) * ull(b) % base;}const ul maxn = 6e6;ul T;ul n;ul inv[maxn + 1];ul sum[maxn + 1];int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);inv[1] = 1;sum[1] = 1;for (ul i = 2; i <= maxn; ++i) {inv[i] = ull(base - base / i) * inv[base % i] % base;sum[i] = plus(sum[i - 1], mul(inv[i], inv[i]));}iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n;oss << mul(mul(sum[n], 3), inv[n]) << '\n';}std::cout << oss.str();return 0;}
如果这个题没有像这样卡空间,其实直接后缀树就行了。
官方题解如下:

#pragma GCC target ("pclmul")#include <bits/stdc++.h>#include <emmintrin.h>#include <wmmintrin.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;using pulul = std::pair<ul, ul>;ul T;ul n, m, q;const ul maxn = 1e6;ul s[maxn + 1];ul tim;ul rk[maxn + 2];ul sa[maxn + 2];ul fa[maxn + 1];std::vector<ul> son[maxn + 2];std::vector<pulul> cnt[maxn + 2];class node {public:ul left = 0;ul right = 0;ul val = 0;node()=default;};std::vector<node> segtree(maxn * 21);ul currroot;void change(ul pos, ul val, ul l, ul r, ul& nid){auto tmpnode = segtree[nid];tmpnode.val += val;if (l != r) {ul midl = l + r >> 1;ul midr = midl + 1;if (pos <= midl) {change(pos, val, l, midl, tmpnode.left);} else {change(pos, val, midr, r, tmpnode.right);}}segtree.push_back(tmpnode);nid = segtree.size() - 1;}ul query(ul l, ul r, ul nl, ul nr, ul nid){if (nl >= l && nr <= r) {return segtree[nid].val;}ul ret = 0;ul midl = nl + nr >> 1;ul midr = midl + 1;if (l <= midl && segtree[nid].left) {ret += query(l, r, nl, midl, segtree[nid].left);}if (r >= midr && segtree[nid].right) {ret += query(l, r, midr, nr, segtree[nid].right);}return ret;}ul head[maxn + 2];void search(ul curr){cnt[curr].resize(0);++tim;ul prevroot = currroot;if (curr != n + 1) {change(s[curr + n + 1 - fa[curr]], 1, 1, m, currroot);}head[curr] = currroot;ul atim = tim;std::sort(son[curr].begin(), son[curr].end(), [&](ul a, ul b){return s[a + n + 1 - curr] < s[b + n + 1 - curr];});for (ul next : son[curr]) {search(next);if (cnt[curr].empty() || cnt[curr].back().first != s[next + n + 1 - curr]) {cnt[curr].push_back(pulul(s[next + n + 1 - curr], 0));}cnt[curr].back().second = tim - atim;}if (curr != n + 1) {currroot = prevroot;}}ul t, c, i;ul s2[maxn + 1], t1[maxn + 1], t2[maxn + 1], cc[maxn + 1];int main(){std::scanf("%u", &T);ul last = 0;for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u%u%u", &n, &m, &q);for (ul i = 1; i <= n; ++i) {std::scanf("%u", &s[i]);son[i].resize(0);}son[n + 1].resize(0);for (ul i = 1; i <= n; ++i) {s2[i] = s[i];}std::sort(s2 + 1, s2 + n + 1);ul newm = std::unique(s2 + 1, s2 + n + 1) - s2 - 1;for (ul i = 1; i <= newm; ++i) {t1[s2[i]] = i;}for (ul i = 1; i <= n; ++i) {s2[i] = t1[s[i]];}ul *x = t1, *y = t2;std::memset(cc + 1, 0, newm * sizeof(ul));for (ul i = 1; i <= n; ++i) {++cc[x[i] = s2[i]];}for (ul i = 1; i <= newm; ++i) {cc[i] += cc[i - 1];}for (ul i = n; i >= 1; --i) {sa[cc[x[i]]] = i;--cc[x[i]];}for (ul k = 1; k <= n; k <<= 1) {ul p = 1;for (ul i = n - k + 1; i <= n; ++i) {y[p] = i;++p;}for (ul i = 1; i <= n; ++i) {if (sa[i] > k) {y[p] = sa[i] - k;++p;}}std::memset(cc + 1, 0, newm * sizeof(ul));for (ul i = 1; i <= n; ++i) {++cc[x[y[i]]];}for (ul i = 1; i <= newm; ++i) {cc[i] += cc[i - 1];}for (ul i = n; i >= 1; --i) {sa[cc[x[y[i]]]] = y[i];--cc[x[y[i]]];}std::swap(x, y);p = 2;x[sa[1]] = 1;for (ul i = 2; i <= n; ++i) {x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;}if (p >= n) break;newm = p;}for (ul i = 1; i <= n; ++i) {rk[sa[i]] = i;}rk[n + 1] = 0;sa[0] = n + 1;fa[n] = n + 1;son[n + 1].push_back(n);for (ul i = n - 1; i >= 1; --i) {ul t;for (t = fa[i + 1]; t != n + 1 && s[t - 1] != s[i]; t = fa[t]);fa[i] = s[t - 1] == s[i] ? t - 1 : t;son[fa[i]].push_back(i);}tim = 0;segtree.resize(0);segtree.resize(1);currroot = 0;search(n + 1);last = 0;for (ul qid = 1; qid <= q; ++qid) {std::scanf("%u%u%u", &t, &c, &i);c ^= last;i ^= last;if (t == 1) {--i;if (i) {bool less;if (c != s[i]) {less = c < s[i];} else {less = rk[1] < rk[i + 1];}if (less) {last = rk[i] + 1;} else {last = rk[i];}} else {ul l = 0, r = n + 1;while (l + 1 != r) {ul mid = l + r >> 1;i = sa[mid];bool less;if (c != s[i]) {less = c < s[i];} else {less = rk[1] < rk[i + 1];}(less ? r : l) = mid;}last = r;}} else {ul tmp = rk[i] + 1;tmp -= query(1, c - 1, 1, m, head[i]);auto it = std::lower_bound(cnt[i].begin(), cnt[i].end(), pulul(c, 0));if (it != cnt[i].begin()) {tmp += std::prev(it)->second;}last = tmp;}std::printf("%u\n", last);}for (ul i = 1; i <= n + 1; ++i) {son[i].clear();cnt[i].clear();}}return 0;}
简单题
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;ul T, n, k;const ul maxk = 10;std::vector<ul> stack[(1 << maxk) + 1];std::vector<ul> out;int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n >> k;stack[1 << k].resize(0);for (ul i = 1; i <= (n << k + 1); ++i) {ul tmp;iss >> tmp;stack[1 << k].push_back(tmp);}std::reverse(stack[1 << k].begin(), stack[1 << k].end());for (ul a = 1; a <= k; ++a) {for (ul s = 1 << k, t = (1 << k) - (1 << a) + 1; s > t; --s, ++t) {stack[t].resize(0);while (stack[s].size() > stack[t].size()) {stack[t].push_back(stack[s].back());stack[s].pop_back();}}}out.resize(0);while (stack[1].size()) {for (ul i = 1; i <= (1 << k); ++i) {out.push_back(stack[i].back());stack[i].pop_back();}}for (ul i = 0; i != out.size(); ++i) {if (i) {oss << ' ';}oss << out[i];}oss << '\n';}std::cout << oss.str();return 0;}
实际问题一并不需要,只需要,注意到
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul mod = 998244353;ul plus(ul a, ul b){return a + b < mod ? a + b : a + b - mod;}ul minus(ul a, ul b){return a < b ? a + mod - b : a - b;}ul mul(ul a, ul b){return ull(a) * ull(b) % mod;}void exgcd(li a, li b, li& x, li& y){if (b) {exgcd(b, a % b, y, x);y -= a / b * x;} else {x = 1;y = 0;}}ul inverse(ul a){li x, y;exgcd(a, mod, x, y);return x < 0 ? x + li(mod) : x;}ul T;const ul maxn = 1e4;ul n, L;class node {public:char op = 0;ul left = 0;ul right = 0;node()=default;node(char op, ul left, ul right): op(op), left(left), right(right) {}};std::vector<node> tree(maxn + maxn);std::vector<char> charstack;std::vector<ul> valstack;ul build(ul left, char op, ul right){tree.push_back(node(op, left, right));return tree.size() - 1;}void onceout(){ul right = valstack.back();valstack.pop_back();ul left = valstack.back();valstack.pop_back();char op = charstack.back();charstack.pop_back();valstack.push_back(build(left, op, right));}ul ans[6][maxn + maxn];ul al[6][maxn + maxn];ul altim;ul head;ul bi[6][6];ul calc(ul t, ul id){if (al[t][id] == altim) {return ans[t][id];}al[t][id] = altim;if (tree[id].op == '+') {return ans[t][id] = plus(calc(t, tree[id].left), calc(t, tree[id].right));} else if (tree[id].op == '-') {return ans[t][id] = minus(calc(t, tree[id].left), calc(t, tree[id].right));} else {ans[t][id] = 0;for (ul i = 0; i <= t; ++i) {ans[t][id] = plus(ans[t][id], mul(mul(bi[t][i], calc(i, tree[id].left)), calc(t - i, tree[id].right)));}return ans[t][id];}}class num {public:ul v = 1;ul cnt0 = 0;num(ul x = 1): v(x ? x : ul(1)), cnt0(!x) {}num(ul x, ul y): v(x), cnt0(y) {}};num operator*(const num& a, const num& b){return num(mul(a.v, b.v), a.cnt0 + b.cnt0);}num f[maxn + maxn];num g[maxn + maxn];ul dfn[maxn + maxn];ul stleft[maxn + maxn][16];ul stright[maxn + maxn][16];ul tim = 0;void search(ul curr){if (tree[curr].left) {if (tree[curr].op == '+' || tree[curr].op == '-') {f[tree[curr].left] = 1;} else {f[tree[curr].left] = calc(0, tree[curr].right);}g[tree[curr].left] = g[curr] * f[tree[curr].left];search(tree[curr].left);}++tim;dfn[curr] = tim;stleft[tim][0] = curr;stright[tim][0] = curr;if (tree[curr].right) {if (tree[curr].op == '+') {f[tree[curr].right] = 1;} else if (tree[curr].op == '-') {f[tree[curr].right] = mod - 1;} else {f[tree[curr].right] = calc(0, tree[curr].left);}g[tree[curr].right] = g[curr] * f[tree[curr].right];search(tree[curr].right);}}ul lca(ul a, ul b){a = dfn[a];b = dfn[b];if (a > b) {std::swap(a, b);}return std::max(stright[a][31 - __builtin_clz(b - a + 1)], stleft[b][31 - __builtin_clz(b - a + 1)]);}const ul maxt = 30;ul is[maxt + 1];int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);for (ul i = 0; i <= 5; ++i) {bi[i][0] = 1;for (ul j = 1; j <= i; ++j) {bi[i][j] = plus(bi[i - 1][j - 1], bi[i - 1][j]);}}iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> L >> n;iss >> instr;charstack.resize(0);valstack.resize(0);tree.resize(0);tree.resize(n + 1);for (auto ch : instr) {if (ch == '[') {valstack.push_back(0);} else if (ch <= '9' && ch >= '0') {valstack.back() *= 10;valstack.back() += ch - '0';} else if (ch == ']') {} else if (ch == '(') {charstack.push_back('(');} else if (ch == ')') {while (charstack.back() != '(') {onceout();}charstack.pop_back();} else if (ch == '*') {while (charstack.size() && charstack.back() == '*') {onceout();}charstack.push_back(ch);} else {while (charstack.size() && (charstack.back() == '*' || charstack.back() == '+' || charstack.back() == '-')) {onceout();}charstack.push_back(ch);}}while (charstack.size()) {onceout();}head = valstack.back();++altim;for (ul i = 1; i <= n; ++i) {li tmp;iss >> tmp;ans[0][i] = (tmp % li(mod) + mod) % mod;al[0][i] = altim;ans[1][i] = 1;al[1][i] = altim;for (ul j = 2; j <= 5; ++j) {ans[j][i] = 0;al[j][i] = altim;}}for (ul i = 0; i <= 5; ++i) {if (i) {oss << ' ';}oss << calc(i, head);}oss << '\n';tim = 0;g[head] = 1;search(head);for (ul i = 1; i <= head; ++i) {for (ul k = 1; (1 << k) <= i; ++k) {stleft[i][k] = std::max(stleft[i][k - 1], stleft[i - (1 << k - 1)][k - 1]);}}for (ul i = head; i >= 1; --i) {for (ul k = 1; i + (1 << k) - 1 <= head; ++k) {stright[i][k] = std::max(stright[i][k - 1], stright[i + (1 << k - 1)][k - 1]);}}ul m;iss >> m;for (ul qid = 1; qid <= m; ++qid) {ul t;iss >> t;for (ul i = 1; i <= t; ++i) {iss >> is[i];}std::sort(is + 1, is + t + 1, [](ul a, ul b){return dfn[a] < dfn[b];});num ans1, ans2;for (ul i = 1; i <= t; ++i) {ans1 = ans1 * g[is[i]];}bool flag = true;for (ul i = 1, j = 2; j <= t; ++i, ++j) {ul l = lca(is[i], is[j]);if (tree[l].op != '*') {flag = false;break;}ans2 = ans2 * g[l] * f[tree[l].left] * f[tree[l].right];}ul ans;if (!flag || ans1.cnt0 != ans2.cnt0) {ans = 0;} else {ans = mul(ans1.v, inverse(ans2.v));}oss << ans << '\n';}}std::cout << oss.str();return 0;}
首先,构成一个个点的有向基环树森林,可以发现,当时,消耗就是减去连通块的数量,而时,消耗就是减去连通块的数量加上叶子的数量。证明很容易,只需要说明两个对应概念在两种操作下的减小量和单步消耗的比值不超过一,且能达到。
叶子数量的期望值很容易求,现在考虑求连通块数量的期望值。用表示中满足连通块数量刚好是的数列的数量(),用表示中所有数列的数量。那么显然,其中。
于是和有如下关系:
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;using vul = std::vector<ul>;const ul base = 998244353;ul plus(ul a, ul b){return a + b < base ? a + b : a + b - base;}ul minus(ul a, ul b){return a < b ? a + base - b : a - b;}ul mul(ul a, ul b){return ull(a) * ull(b) % base;}void exgcd(li a, li b, li& x, li& y){if (b) {exgcd(b, a % b, y, x);y -= x * (a / b);} else {x = 1;y = 0;}}ul inverse(ul a){li x, y;exgcd(a, base, x, y);return x < 0 ? x + li(base) : x;}ul pow(ul a, ul b){ul ret = 1;ul temp = a;while (b) {if (b & 1) {ret = mul(ret, temp);}temp = mul(temp, temp);b >>= 1;}return ret;}class polynomial : public vul {public:void clearzero() {while (size() && !back()) {pop_back();}}polynomial()=default;polynomial(const vul& a): vul(a) { }polynomial(vul&& a): vul(std::move(a)) { }ul degree() const {return size() - 1;}ul operator()(ul x) const {ul ret = 0;for (ul i = size() - 1; ~i; --i) {ret = mul(ret, x);ret = plus(ret, vul::operator[](i));}return ret;}};polynomial& operator+=(polynomial& a, const polynomial& b){a.resize(std::max(a.size(), b.size()), 0);for (ul i = 0; i != b.size(); ++i) {a[i] = plus(a[i], b[i]);}a.clearzero();return a;}polynomial operator+(const polynomial& a, const polynomial& b){polynomial ret = a;return ret += b;}polynomial& operator-=(polynomial& a, const polynomial& b){a.resize(std::max(a.size(), b.size()), 0);for (ul i = 0; i != b.size(); ++i) {a[i] = minus(a[i], b[i]);}a.clearzero();return a;}polynomial operator-(const polynomial& a, const polynomial& b){polynomial ret = a;return ret -= b;}class ntt_t {public:static const ul lgsz = 20;static const ul sz = 1 << lgsz;static const ul g = 3;ul w[sz + 1];ul leninv[lgsz + 1];ntt_t() {ul wn = pow(g, (base - 1) >> lgsz);w[0] = 1;for (ul i = 1; i <= sz; ++i) {w[i] = mul(w[i - 1], wn);}leninv[lgsz] = inverse(sz);for (ul i = lgsz - 1; ~i; --i) {leninv[i] = plus(leninv[i + 1], leninv[i + 1]);}}void operator()(vul& v, ul& n, bool inv) {ul lgn = 0;while ((1 << lgn) < n) {++lgn;}n = 1 << lgn;v.resize(n, 0);for (ul i = 0, j = 0; i != n; ++i) {if (i < j) {std::swap(v[i], v[j]);}ul k = n >> 1;while (k & j) {j &= ~k;k >>= 1;}j |= k;}for (ul lgmid = 0; (1 << lgmid) != n; ++lgmid) {ul mid = 1 << lgmid;ul len = mid << 1;for (ul i = 0; i != n; i += len) {for (ul j = 0; j != mid; ++j) {ul t0 = v[i + j];ul t1 = mul(w[inv ? (len - j << lgsz - lgmid - 1) : (j << lgsz - lgmid - 1)], v[i + j + mid]);v[i + j] = plus(t0, t1);v[i + j + mid] = minus(t0, t1);}}}if (inv) {for (ul i = 0; i != n; ++i) {v[i] = mul(v[i], leninv[lgn]);}}}} ntt;polynomial& operator*=(polynomial& a, const polynomial& b){if (!b.size() || !a.size()) {a.resize(0);return a;}polynomial temp = b;ul npmp1 = a.size() + b.size() - 1;if (ull(a.size()) * ull(b.size()) <= ull(npmp1) * ull(50)) {temp.resize(0);temp.resize(npmp1, 0);for (ul i = 0; i != a.size(); ++i) {for (ul j = 0; j != b.size(); ++j) {temp[i + j] = plus(temp[i + j], mul(a[i], b[j]));}}a = temp;a.clearzero();return a;}ntt(a, npmp1, false);ntt(temp, npmp1, false);for (ul i = 0; i != npmp1; ++i) {a[i] = mul(a[i], temp[i]);}ntt(a, npmp1, true);a.clearzero();return a;}polynomial operator*(const polynomial& a, const polynomial& b){polynomial ret = a;return ret *= b;}polynomial& operator*=(polynomial& a, ul b){if (!b) {a.resize(0);return a;}for (ul i = 0; i != a.size(); ++i) {a[i] = mul(a[i], b);}return a;}polynomial operator*(const polynomial& a, ul b){polynomial ret = a;return ret *= b;}polynomial inverse(const polynomial& a, ul lgdeg){polynomial ret({inverse(a[0])});polynomial temp;polynomial tempa;for (ul i = 0; i != lgdeg; ++i) {tempa.resize(0);tempa.resize(1 << i << 1, 0);for (ul j = 0; j != tempa.size() && j != a.size(); ++j) {tempa[j] = a[j];}temp = ret * (polynomial({2}) - tempa * ret);if (temp.size() > (1 << i << 1)) {temp.resize(1 << i << 1, 0);}temp.clearzero();std::swap(temp, ret);}return ret;}polynomial diffrential(const polynomial& a){if (!a.size()) {return a;}polynomial ret(vul(a.size() - 1, 0));for (ul i = 1; i != a.size(); ++i) {ret[i - 1] = mul(a[i], i);}return ret;}polynomial integral(const polynomial& a){polynomial ret(vul(a.size() + 1, 0));for (ul i = 0; i != a.size(); ++i) {ret[i + 1] = mul(a[i], inverse(i + 1));}return ret;}polynomial ln(const polynomial& a, ul lgdeg){polynomial da = diffrential(a);polynomial inva = inverse(a, lgdeg);polynomial ret = integral(da * inva);if (ret.size() > (1 << lgdeg)) {ret.resize(1 << lgdeg);ret.clearzero();}return ret;}const ul maxn = 5e5;ul fac[maxn + 1];ul fiv[maxn + 1];int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);ul n;iss >> n;fac[0] = 1;for (ul i = 1; i <= n; ++i) {fac[i] = mul(fac[i - 1], i);}fiv[n] = inverse(fac[n]);for (ul i = n; i >= 1; --i) {fiv[i - 1] = mul(fiv[i], i);}polynomial g(vul(n + 1));g[0] = 1;for (ul i = 1; i <= n; ++i) {g[i] = mul(fiv[i], pow(i, i));}polynomial f = ln(g, 32 - __builtin_clz(n));f.resize(n + 1);polynomial h = f * g;h.resize(n + 1);for (ul i = 1; i <= n; ++i) {ul tmp = mul(h[i], fac[i]);ul tmp2 = inverse(mul(g[i], fac[i]));oss << "0 " << minus(i, mul(tmp, tmp2)) << ' ' << plus(minus(i, mul(tmp, tmp2)), mul(mul(pow(i - 1, i), tmp2), i)) << '\n';}std::cout << oss.str();return 0;}
官方题解如下,很清楚:

#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul maxn = 1e5;ul T;ul n, v, q, k;ul stack[maxn + 1];ul cnt;ul num[maxn + 1];ul al[maxn + 1];int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n >> v >> q >> k;cnt = 0;for (ul i = 1; i <= q; ++i) {ul tmp;iss >> tmp;al[tmp] = Case;ul it = std::lower_bound(stack + 1, stack + cnt + 1, tmp) - stack;cnt = std::max(cnt, it);stack[it] = tmp;}std::memset(num + 1, 0, k * sizeof(ul));for (ul i = 1; i <= n; ++i) {if (al[i] != Case) {ul it = std::lower_bound(stack + 1, stack + cnt + 1, i) - stack;++num[it];}}if (v == 1) {if (num[k] > 0) {oss << "YES " << num[k] << '\n';} else {ul sum = 0;for (ul i = 1; i + 1 <= k; ++i) {sum += num[i];}if (sum & 1) {oss << "YES " << sum - num[k - 1] + (num[k - 1] > 0) << '\n';} else {oss << "NO\n";}}} else {if (num[k - 1] >= 2) {oss << "YES 1\n";} else {ul sum = 0;for (ul i = 1; i + 1 <= k; ++i) {sum += num[i];}if (sum & 1) {oss << "YES " << (num[k - 1] ? 1 + (num[k - 2] > 0) : (num[k - 2] > 0) + (num[k - 2] > 1)) + sum - num[k - 1] - num[k - 2] << '\n';} else {oss << "NO\n";}}}}std::cout << oss.str();return 0;}
简单题
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;using pullull = std::pair<ull, ull>;const ul maxn = 2e5;ul T;ul n, k;class edge_t {public:ul to = 0;ul d = 0;edge_t()=default;edge_t(ul a, ul b): to(a), d(b) {}};std::vector<edge_t> edge[maxn + 1];ull ans[maxn + 1][5];ull outans;void search(ul curr, ul prev){static std::vector<pullull> stack;for (const auto& e : edge[curr]) {ul next = e.to;if (next == prev) {continue;}search(next, curr);}stack.resize(0);for (const auto& e : edge[curr]) {ul next = e.to;if (next == prev) {continue;}stack.push_back(pullull(e.d + ans[next][0], e.d + ans[next][6]));}std::sort(stack.rbegin(), stack.rend());ans[curr][0] = ans[curr][7] = ans[curr][8] = ans[curr][9] = 0;for (ul i = 0; i + 1 < k && i != stack.size(); ++i) {ans[curr][0] += stack[i].first;}for (ul i = 0; i < k && i != stack.size(); ++i) {ans[curr][10] += stack[i].first;}if (k >= 1) {for (ul i = 0; i != stack.size(); ++i) {ans[curr][11] += stack[i].first;ans[curr][12] += stack[i].first;}}if (k >= 2) {ull tmp = 0;for (ul i = 0; i != k - 2 && i != stack.size(); ++i) {tmp += stack[i].first;}ull tmp2 = 0;for (ul i = k - 2; i < stack.size(); ++i) {tmp2 = std::max(tmp2, stack[i].second);}tmp += tmp2;tmp2 = 0;ull tmp3 = 0;for (ul i = 0; i != k - 1 && i != stack.size(); ++i) {tmp2 += stack[i].first;tmp3 = std::max(tmp3, stack[i].second - stack[i].first);}tmp = std::max(tmp, tmp3 + tmp2);ans[curr][13] = std::max(ans[curr][14], tmp);}if (k >= 1) {ull tmp = 0;for (ul i = 0; i != k - 1 && i != stack.size(); ++i) {tmp += stack[i].first;}ull tmp2 = 0;for (ul i = k - 1; i < stack.size(); ++i) {tmp2 = std::max(tmp2, stack[i].second);}tmp += tmp2;tmp2 = 0;ull tmp3 = 0;for (ul i = 0; i != k && i != stack.size(); ++i) {tmp2 += stack[i].first;tmp3 = std::max(tmp3, stack[i].second - stack[i].first);}tmp = std::max(tmp, tmp3 + tmp2);ans[curr][15] = std::max(ans[curr][16], tmp);}outans = std::max(outans, ans[curr][17]);outans = std::max(outans, ans[curr][18]);}int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n >> k;for (ul i = 1; i <= n; ++i) {edge[i].resize(0);}for (ul i = 1; i <= n - 1; ++i) {ul u, v, d;iss >> u >> v >> d;edge[u].push_back(edge_t(v, d));edge[v].push_back(edge_t(u, d));}if (!k) {oss << "0\n";continue;}outans = 0;search(1, 0);oss << outans << '\n';}std::cout << oss.str();return 0;}
设表示在有个数的情况,存活的概率,递推即可。
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul mod = 998244353;ul plus(ul a, ul b){return a + b < mod ? a + b : a + b - mod;}ul minus(ul a, ul b){return a < b ? a + mod - b : a - b;}ul mul(ul a, ul b){return ull(a) * ull(b) % mod;}void exgcd(li a, li b, li& x, li& y){if (b) {exgcd(b, a % b, y, x);y -= a / b * x;} else {x = 1;y = 0;}}ul inverse(ul a){li x, y;exgcd(a, mod, x, y);return x < 0 ? x + li(mod) : x;}const ul maxn = 5e3;ul T, n, k;ul fac[maxn + 1];ul fiv[maxn + 1];ul ans[maxn + 1][maxn + 1];ul bi(ul a, ul b){return mul(fac[a], mul(fiv[a - b], fiv[b]));}ul biv(ul a, ul b){return mul(fiv[a], mul(fac[a - b], fac[b]));}int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);fac[0] = 1;for (ul i = 1; i <= maxn; ++i) {fac[i] = mul(fac[i - 1], i);}fiv[maxn] = inverse(fac[maxn]);for (ul i = maxn; i >= 1; --i) {fiv[i - 1] = mul(fiv[i], i);}iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n >> k;ul alpha = n % (k + 1);for (ul i = 1; i <= alpha; ++i) {ans[alpha][i] = 1;}for (ul r = alpha + k + 1; r <= n; r += k + 1) {ans[r][19] = 0;ul tmp = biv(r - 1, k);for (ul i = 2; i <= r; ++i) {ans[r][i] = 0;for (ul j = std::max(k + i, r) - r; j <= std::min(k, i - 2); ++j) {ans[r][i] = plus(ans[r][i], mul(ans[r - k - 1][i - j - 1], mul(bi(i - 2, j), bi(r - i, k - j))));}ans[r][i] = mul(ans[r][i], tmp);}}for (ul i = 1; i <= n; ++i) {if (i != 1) {oss << ' ';}oss << ans[n][i];}oss << '\n';}std::cout << oss.str();return 0;}
倒着考虑,每当上下展开的时候,行数变为原先两倍减一,每当左右展开的时候,列数变为原先两倍减一。
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul mod = 998244353;ul plus(ul a, ul b){return a + b < mod ? a + b : a + b - mod;}ul minus(ul a, ul b){return a < b ? a + mod - b : a - b;}ul mul(ul a, ul b){return ull(a) * ull(b) % mod;}void exgcd(li a, li b, li& x, li& y){if (b) {exgcd(b, a % b, y, x);y -= a / b * x;} else {x = 1;y = 0;}}ul inverse(ul a){li x, y;exgcd(a, mod, x, y);return x < 0 ? x + li(mod) : x;}ul pow(ul a, ul b){ul ret = 1;while (b) {if (b & 1) {ret = mul(ret, a);}a = mul(a, a);b >>= 1;}return ret;}ul inv2 = inverse(2);ul T;ull n;int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n;n %= mod - 1;oss << plus(plus(pow(2, ul(n)), mul(mul(pow(3, ul(n)), 2), pow(inv2, ul(n)))), 1) << '\n';}std::cout << oss.str();return 0;}
题意实际就是要求作为的线性变换,其若当型中所有若当块形如。
于是构造就很容易了。关键是检查,检查详细步骤会在代码中注释出来,关于此检查步骤的必要性和充分性请自己证明。
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;ul T;ul n, m;const ul maxd = 60;const ul maxm = 2e5;std::vector<ull> base;char op[20];char so[40];class xy {public:ull x = 0;ll y = 0;};std::vector<xy> base2;std::vector<xy> base3;xy s;std::vector<ull> tmp;std::vector<ull> base4;int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n;base.resize(0);for (ul i = 1; i <= n; ++i) {ull a;iss >> a;for (auto v : base) {a = std::min(a, a ^ v);}if (a) {base.push_back(a);}}iss >> op + 1;if (op[2] == 'o') {if (base.size() & 1) {oss << "NoSolution\n";iss >> m;for (ul c = 1; c <= m; ++c) {ull x;iss >> x;}continue;} else {oss << "HaveSolution\n";iss >> m;ul t = base.size() >> 1;for (ul c = 1; c <= m; ++c) {ull x;ull y = 0;iss >> x;for (ul i = 0; i != t; ++i) {if ((x ^ base[i]) < x) {x ^= base[i];y ^= base[i + t];}}for (ul i = t; i != base.size(); ++i) {x = std::min(x, x ^ base[i]);}if (x) {oss << "-1\n";} else {oss << y << '\n';}}}} else {iss >> so + 1;if (base.size() & 1) {//如果S(a)维度为奇数,显然不可行if (so[1] == 'N') {oss << "Yes\n";continue;} else {oss << "No\n";iss >> m;for (ul c = 1; c <= m; ++c) {ull x;ll y;iss >> x >> y;}continue;}} else {if (so[1] == 'N') {//如果维度为偶数,显然可行oss << "No\n";continue;} else {iss >> m;ul t = base.size() >> 1;bool flag = true;base2.resize(0);for (ul c = 1; c <= m; ++c) {iss >> s.x >> s.y;if (!flag) {continue;}if (s.y == -1) {//确认x是不是确实在S(a)外for (auto v : base) {s.x = std::min(s.x ^ v, s.x);}if (s.x == 0) {flag = false;}continue;}for (const auto& v : base2) {//保证不丢失信息的情况下,检查f的线性性if ((s.x ^ v.x) < s.x) {s.x ^= v.x;s.y ^= v.y;}}if (s.x == 0 && s.y != 0) {flag = false;continue;}if (s.x) {base2.push_back(s);}}if (!flag) {oss << "No\n";continue;}for (auto s : base2) {//检查是否所有插值点的输入和输出都在S(a)中for (auto v : base) {s.x = std::min(s.x, s.x ^ v);}for (auto v : base) {s.y = std::min(ull(s.y), s.y ^ v);}if (s.x || s.y) {flag = false;break;}}if (!flag) {oss << "No\n";continue;}base3.resize(0);tmp.resize(0);for (auto s : base2) {//在不丢失信息的情况下,求出y所张成的子空间(也就是插值点间接提供的核子空间,由于要求f(y)=0),并确认插值点直接提供的核子空间for (auto v : base3) {if ((s.y ^ v.y) < s.y) {s.y ^= v.y;s.x ^= v.x;}}if (s.y) {base3.push_back(s);} else {tmp.push_back(s.x);}}base4.resize(0);for (auto s : base3) {//接下来两个for将使得base4就是插值点直接以及间接给出的核子空间base4.push_back(s.y);}for (auto s : tmp) {for (auto v : base4) {s = std::min(s, s ^ v);}if (s) {base4.push_back(s);}}if (base4.size() * 2 > base.size()) {//如果核子空间的维度大于了S(a)维度的一半,肯定不行flag = false;}if (!flag) {oss << "No\n";continue;}for (auto s : base3) {//最后,再检查那些x和y是否独立(这是关键要完成的证明,必要性就是说明这些如果不独立则肯定不行,充分性就是说明这些如果独立就一定能张出合适的f)for (auto v : base4) {s.x = std::min(s.x, s.x ^ v);}if (s.x) {base4.push_back(s.x);} else {flag = false;break;}}if (!flag) {oss << "No\n";continue;}oss << "Yes\n";}}}}std::cout << oss.str();return 0;}
2SAT,线段树建图
#include <bits/stdc++.h>namespace fast_pool {constexpr size_t const size = 481 << 20;unsigned char data[size];unsigned char* ptr = data;void clear() {ptr = data;}void* fast_alloc(size_t n) {ptr += n; return ptr - n;}};template<class T>class myallocator {public:typedef T value_type;typedef value_type* pointer;typedef value_type& reference;typedef value_type const* const_pointer;typedef value_type const& const_reference;typedef size_t size_type;typedef ptrdiff_t difference_type;pointer allocate(size_t n, const T* pHint = 0) {return (pointer)(fast_pool::fast_alloc(n * sizeof(T)));}void deallocate(pointer p, size_type n) {}void destroy(T* p) {p->~T();}void construct(T* p, const T& val) {::new((void *)p) T(val);}size_t max_size() const throw() {return (fast_pool::size + fast_pool::data - fast_pool::ptr) / sizeof(T);}T* address(T& val) const {return &val;}const T* address(const T& val) const {return &val;}myallocator() throw() {}myallocator(const T* p) throw() {}~myallocator() throw() {}template <typename _other> struct rebind { typedef myallocator<_other> other; };};std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;ul T;ul n;const ul maxn = 25000;class seg_t {public:ul l = 0;ul r = 0;seg_t()=default;};class exam_t {public:seg_t a;seg_t b;exam_t()=default;};exam_t exam[maxn + 1];std::pair<seg_t, ul> props[maxn * 2 + 1];const ul maxsz = 1 << 16;ul sz;ul cnt;ul down[maxsz << 1];ul up[maxsz << 1];std::vector<ul, myallocator<ul>> edges[199959];void addedge(ul l, ul r, ul pid){for (l = l - 1 | sz, r = r + 1 | sz; l ^ r ^ 1; l >>= 1, r >>= 1) {if (~l & 1) {edges[up[l ^ 1]].push_back(pid * 2);edges[pid * 2 - 1].push_back(down[l ^ 1]);}if (r & 1) {edges[up[r ^ 1]].push_back(pid * 2);edges[pid * 2 - 1].push_back(down[r ^ 1]);}}}ul low[199959];ul dfn[199959];std::vector<ul, myallocator<ul>> stack(199958);std::vector<bool> instack(199959);ul tim;void search(ul v, const std::vector<ul, myallocator<ul>> edges[], std::vector<std::vector<ul, myallocator<ul>>, myallocator<std::vector<ul, myallocator<ul>>>>& sccs){low[v] = dfn[v] = ++tim;stack.push_back(v);instack[v] = true;for (ul w : edges[v]) {if (!dfn[w]) {search(w, edges, sccs);low[v] = std::min(low[v], low[w]);} else if (dfn[w] < dfn[v]) {if (instack[w]) {low[v] = std::min(low[v], dfn[w]);}}}if (low[v] == dfn[v]) {sccs.push_back(std::vector<ul, myallocator<ul>>());while (stack.size() && dfn[stack.back()] >= dfn[v]) {instack[stack.back()] = false;sccs.back().push_back(stack.back());stack.pop_back();}}}void scc(const std::vector<ul, myallocator<ul>> edges[], ul sz, std::vector<std::vector<ul, myallocator<ul>>, myallocator<std::vector<ul, myallocator<ul>>>>& sccs){sccs.resize(0);tim = 0;stack.resize(0);instack.resize(0);instack.resize(sz + 1, false);std::memset(dfn + 1, 0, sz * sizeof(ul));for (ul w = 1; w <= sz; ++w) {if (!dfn[w]) {search(w, edges, sccs);}}}std::vector<std::vector<ul, myallocator<ul>>, myallocator<std::vector<ul, myallocator<ul>>>> sccs;ul already[maxn + maxn + maxn + maxn + 1];ul altim = 0;int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n;ul mx = 0, mn = 0;for (ul i = 1; i <= n; ++i) {iss >> exam[i].a.l >> exam[i].a.r >> exam[i].b.l >> exam[i].b.r;exam[i].a.r += exam[i].a.l;exam[i].b.r += exam[i].b.l;mx = std::max(mx, std::max(exam[i].a.r, exam[i].b.r));mn = std::max(mn, std::min(exam[i].a.r, exam[i].b.r));props[i * 2 - 1] = std::pair<seg_t, ul>(exam[i].a, i * 2 - 1);props[i * 2] = std::pair<seg_t, ul>(exam[i].b, i * 2);}std::sort(props + 1, props + 2 * n + 1, [](const std::pair<seg_t, ul>& a, const std::pair<seg_t, ul>& b){return a.first.l < b.first.l;});sz = 1;ul lgsz = 0;while (n * 2 + 2 > sz) {sz <<= 1;++lgsz;}cnt = n * 4;std::memset(down, 0, (sz << 1) * sizeof(ul));std::memset(up, 0, (sz << 1) * sizeof(ul));for (ul depth = 0; (1 << depth) < sz; ++depth) {for (ul i = 0; i != (1 << depth); ++i) {ul l = i << lgsz - depth;ul r = (i + 1 << lgsz - depth) - 1;if (l < 1 || r > 2 * n) {continue;}++cnt;down[1 << depth | i] = cnt;++cnt;up[1 << depth | i] = cnt;}}for (ul i = 1; i <= n + n; ++i) {down[sz | i] = props[i].second * 2;up[sz | i] = props[i].second * 2 - 1;}for (ul i = 1; i <= cnt; ++i) {edges[i].resize(0);}for (ul i = 1; i <= n; ++i) {edges[i * 4 - 2].push_back(i * 4 - 1);edges[i * 4].push_back(i * 4 - 3);}for (ul i = 1; i != sz; ++i) {if (!down[i]) {continue;}edges[down[i]].push_back(down[i << 1]);edges[down[i]].push_back(down[i << 1 | 1]);edges[up[i << 1]].push_back(up[i]);edges[up[i << 1 | 1]].push_back(up[i]);}for (ul i = 1; i <= n + n; ++i) {ul it1 = std::lower_bound(props + 1, props + i, props[i], [](const std::pair<seg_t, ul>& a, const std::pair<seg_t, ul>& b){return a.first.l < b.first.l;}) - props;auto tmp = props[i];tmp.first.l = tmp.first.r;ul it2 = std::upper_bound(props + i + 1, props + n + n + 1, tmp, [](const std::pair<seg_t, ul>& a, const std::pair<seg_t, ul>& b){return a.first.l < b.first.l;}) - props - 1;addedge(it1, i - 1, props[i].second);addedge(i + 1, it2, props[i].second);}ul l = mn - 1, r = mx + 1;while (l + 1 != r) {ul mid = l + r >> 1;for (ul i = 1; i <= n + n; ++i) {if (props[i].first.r > mid) {edges[props[i].second * 2 - 1].push_back(props[i].second * 2);}}scc(edges, cnt, sccs);bool flag = true;for (auto& scc : sccs) {++altim;for (auto v : scc) {if (v > n * 4) {continue;}if ((v & 1) && already[v + 1] == altim || (~v & 1) && already[v - 1] == altim) {flag = false;break;}already[v] = altim;}if (!flag) {break;}}if (flag) {r = mid;} else {l = mid;}for (ul i = 1; i <= n + n; ++i) {if (props[i].first.r > mid) {edges[props[i].second * 2 - 1].pop_back();}}}oss << (r != mx + 1 ? li(r) : li(-1)) << '\n';}std::cout << oss.str();return 0;}
官方题解如下:
注意,图片中少除以了一样东西,很容易看出来。
#include <bits/stdc++.h>std::stringstream iss;std::stringstream oss;std::string instr;using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;ul T;ul n;const ul mod = 998244353;ul plus(ul a, ul b){return a + b < mod ? a + b : a + b - mod;}ul mul(ul a, ul b){return ull(a) * ull(b) % mod;}void exgcd(li a, li b, li& x, li& y){if (b) {exgcd(b, a % b, y, x);y -= a / b * x;} else {x = 1;y = 0;}}ul inverse(ul a){li x, y;exgcd(a, mod, x, y);return x < 0 ? x + li(mod) : x;}const ul maxn = 5e6;ul fac[maxn + 1];ul fiv[maxn + 1];ul twopow[maxn + 1];ul twopowinv[maxn + 1];int main(){std::ios::sync_with_stdio(false);std::cin.tie(0);iss.tie(0);oss.tie(0);std::getline(std::cin, instr, char(0));iss.str(instr);fac[0] = 1;twopow[0] = 1;for (ul i = 1; i <= maxn; ++i) {fac[i] = mul(fac[i - 1], i);twopow[i] = plus(twopow[i - 1], twopow[i - 1]);}fiv[maxn] = inverse(fac[maxn]);twopowinv[maxn] = inverse(twopow[maxn]);for (ul i = maxn; i >= 1; --i) {fiv[i - 1] = mul(fiv[i], i);twopowinv[i - 1] = plus(twopowinv[i], twopowinv[i]);}iss >> T;for (ul Case = 1; Case <= T; ++Case) {iss >> n;ul lambda = mul(fiv[n >> 1], twopowinv[n >> 1]);ul sum = 0;for (ul i = 1; i <= n; ++i) {if (i != 1) {oss << ' ';}if (n - i > i - 1) {oss << '0';continue;}oss << mul(mul(mul(fac[i - 1], twopowinv[i - (n + 1 >> 1)]), fiv[i - (n + 1 >> 1)]), lambda);}oss << '\n';}std::cout << oss.str();return 0;}