@qq290637843
2021-03-22T10:14:46.000000Z
字数 27331
阅读 315
题目见https://ac.nowcoder.com/acm/contest/4370
首先预处理出每个块上下左右四个方向分别有多少个块。
考虑型的数法,将块按照的值分类,那么自然地,以的形作为插入,以的形作为查询点,就变成插入一些区间,以及查询一些区间,当且仅当时插入区间和查询区间耦合,此问题考虑按照区间右端点从大到小排列,于是对每一个查询区间只需要考虑其内有多少个插入区间的左端点。
#include <bits/stdc++.h>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 = 1e6;class data {public:ul xp = 0;ul yp = 0;ul xm = 0;ul ym = 0;};data map[maxn + 1];ul tot1;ull stack1[maxn + 1];ul calcxp(ul x, ul y){ull v = ull(x) << 32 | y;auto it = std::lower_bound(stack1 + 1, stack1 + tot1 + 1, v) - stack1;if (it == tot1 + 1 || stack1[it] != v) {return 0;} else if (map[it].xp) {return map[it].xp;} else {return map[it].xp = calcxp(x + 1, y) + 1;}}ul calcyp(ul x, ul y){ull v = ull(x) << 32 | y;auto it = std::lower_bound(stack1 + 1, stack1 + tot1 + 1, v) - stack1;if (it == tot1 + 1 || stack1[it] != v) {return 0;} else if (map[it].yp) {return map[it].yp;} else {return map[it].yp = calcyp(x, y + 1) + 1;}}ul calcxm(ul x, ul y){ull v = ull(x) << 32 | y;auto it = std::lower_bound(stack1 + 1, stack1 + tot1 + 1, v) - stack1;if (it == tot1 + 1 || stack1[it] != v) {return 0;} else if (map[it].xm) {return map[it].xm;} else {return map[it].xm = calcxm(x - 1, y) + 1;}}ul calcym(ul x, ul y){ull v = ull(x) << 32 | y;auto it = std::lower_bound(stack1 + 1, stack1 + tot1 + 1, v) - stack1;if (it == tot1 + 1 || stack1[it] != v) {return 0;} else if (map[it].ym) {return map[it].ym;} else {return map[it].ym = calcym(x, y - 1) + 1;}}ul tree[1 << 22];ul sz;ul query(ul l, ul r){ul ret = 0;for (l = l - 1 | sz, r = r + 1 | sz; l ^ r ^ 1; l >>= 1, r >>= 1) {if (~l & 1) {ret += tree[l ^ 1];}if (r & 1) {ret += tree[r ^ 1];}}return ret;}void change(ul pos, ul v){for (pos |= sz; pos; pos >>= 1) {tree[pos] += v;}}class seg {public:ul f = 0;ul b = 0;bool insert = false;seg()=default;seg(ul x, ul y, bool z): f(x), b(y), insert(z) {}};ul datas[maxn + maxn + 1];ul tot;ul stack2[maxn + maxn + 1];ul tot2;std::vector<seg> blobs[maxn + maxn + 1];std::vector<seg>& at(ul v){return blobs[std::lower_bound(stack2 + 1, stack2 + tot2 + 1, v) - stack2];}int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u", &n);tot1 = 0;tot2 = 0;for (ul i = 1; i <= n; ++i) {ul x, y;std::scanf("%u%u", &x, &y);++tot1;stack1[tot1] = ull(x) << 32 | y;map[tot1] = data();}std::sort(stack1 + 1, stack1 + tot1 + 1);for (ul it = 1; it <= tot1; ++it) {ull tmp = stack1[it];calcxp(tmp >> 32, tmp);calcyp(tmp >> 32, tmp);calcxm(tmp >> 32, tmp);calcym(tmp >> 32, tmp);}ul ans = 0;tot2 = 0;for (ul it = 1; it <= tot1; ++it) {ul x = stack1[it] >> 32;ul y = stack1[it];++tot2;stack2[tot2] = x + x + y;++tot2;stack2[tot2] = x + x + y + 1;}std::sort(stack2 + 1, stack2 + tot2 + 1);tot2 = std::unique(stack2 + 1, stack2 + tot2 + 1) - stack2 - 1;for (ul i = 1; i <= tot2; ++i) {blobs[i].resize(0);}for (ul it = 1; it <= tot1; ++it) {ul x = stack1[it] >> 32;ul y = stack1[it];at(x + x + y).push_back(seg(x, x + std::min(map[it].xp, map[it].ym >> 1) - 1, true));at(x + x + y + 1).push_back(seg(x - std::min(map[it].xm, map[it].yp >> 1) + 1, x, false));}for (ul it = 1; it <= tot2; ++it) {std::sort(blobs[it].begin(), blobs[it].end(), [](const seg& a, const seg& b){return a.b != b.b ? a.b > b.b : a.insert > b.insert;});tot = 0;for (const auto& s : blobs[it]) {++tot;datas[tot] = s.f;datas[tot] = s.b;}std::sort(datas + 1, datas + tot + 1);tot = std::unique(datas + 1, datas + tot + 1) - datas - 1;sz = 1;while (sz < tot + 2) {sz <<= 1;}std::memset(tree, 0, sizeof(ul) * (sz << 1));for (const auto& s : blobs[it]) {ul f = std::lower_bound(datas + 1, datas + tot + 1, s.f) - datas;ul b = std::lower_bound(datas + 1, datas + tot + 1, s.b) - datas;if (s.insert) {change(f, 1);} else {ans += query(f, b);}}}tot2 = 0;for (ul it = 1; it <= tot1; ++it) {ul x = stack1[it] >> 32;ul y = stack1[it];++tot2;stack2[tot2] = x + y + y;++tot2;stack2[tot2] = x + y + y + 1;}std::sort(stack2 + 1, stack2 + tot2 + 1);tot2 = std::unique(stack2 + 1, stack2 + tot2 + 1) - stack2 - 1;for (ul i = 1; i <= tot2; ++i) {blobs[i].resize(0);}for (ul it = 1; it <= tot1; ++it) {ul x = stack1[it] >> 32;ul y = stack1[it];at(x + y + y).push_back(seg(y, y + std::min(map[it].yp, map[it].xm >> 1) - 1, true));at(x + y + y + 1).push_back(seg(y - std::min(map[it].ym, map[it].xp >> 1) + 1, y, false));}for (ul it = 1; it <= tot2; ++it) {std::sort(blobs[it].begin(), blobs[it].end(), [](const seg& a, const seg& b){return a.b != b.b ? a.b > b.b : a.insert > b.insert;});tot = 0;for (const auto& s : blobs[it]) {++tot;datas[tot] = s.f;datas[tot] = s.b;}std::sort(datas + 1, datas + tot + 1);tot = std::unique(datas + 1, datas + tot + 1) - datas - 1;sz = 1;while (sz < tot + 2) {sz <<= 1;}std::memset(tree, 0, sizeof(ul) * (sz << 1));for (const auto& s : blobs[it]) {ul f = std::lower_bound(datas + 1, datas + tot + 1, s.f) - datas;ul b = std::lower_bound(datas + 1, datas + tot + 1, s.b) - datas;if (s.insert) {change(f, 1);} else {ans += query(f, b);}}}std::printf("Case #%u: %u\n", Case, ans);}return 0;}
简单题
#include <bits/stdc++.h>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 = 1e4;std::unordered_set<ull> set;ull data[maxn + 1];char str[12];int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u", &n);for (ul i = 1; i <= n; ++i) {std::scanf("%s", str + 1);data[i] = 1;for (ul j = 1; str[j]; ++j) {data[i] *= 10;data[i] += str[j] - '0';}}bool flag = true;set.clear();for (ul i = 1; i <= n; ++i) {if (set.find(data[i]) != set.end()) {flag = false;break;}ull tmp = data[i];while (tmp) {set.insert(tmp);tmp /= 10;}}if (flag) {set.clear();for (ul i = n; i >= 1; --i) {if (set.find(data[i]) != set.end()) {flag = false;break;}ull tmp = data[i];while (tmp) {set.insert(tmp);tmp /= 10;}}}std::printf("Case #%u: %s\n", Case, flag ? "Yes" : "No");}return 0;}
先解决一个子问题:从出发,到,满足在过程中且的路径数量。考虑容斥,将两条直线叫做和,那么所有违法路径一定有接触两条直线的顺序。现在考虑其接触过,这意味着,其最后一次接触之后的路径全都依对称,正好和从出发到的路线一一对应,而这样的路线一定以或者的顺序收尾。同理,以或者的顺序收尾的路线和从出发到的路线一一对应。直接减掉这两部分之后,还需要将以或以收尾的路线加回来,因为重复减掉了。而继续迭代,以或以收尾的路线,先将最后一次接触之后的路线依对称,再将最后一次接触之后的路线依对称,就和从出发到的路线一一对应了。于是一直这样迭代并乘上容斥系数就能刚好只减去以或结尾的路线。
关于必须经过以及必不经过的点再容斥就是了。
#include <bits/stdc++.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul mod = 1e9 + 7;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;ul n, m, s, k;const ul maxn = 1e5;const ul maxm = 1e5;const ul maxs = 10;const ul maxk = 20;std::pair<ul, ul> c[maxs + maxk + 2 + 1];ul tot;ul fac[maxn + maxm + 1];ul fiv[maxn + maxm + 1];ul calc(ul a, ul b){return mul(fac[a + b], mul(fiv[a], fiv[b]));}ul f(ul n, ul m, ul t1, ul t2){ul ret = calc(n, m);for (ul a = n, b = m, p = 1; ; p = !p) {std::swap(a, b);if (p) {if (a < t1) {break;}a -= t1;b += t1;ret = minus(ret, calc(a, b));} else {if (b < t2) {break;}a += t2;b -= t2;ret = plus(ret, calc(a, b));}}for (ul a = n, b = m, p = 1; ; p = !p) {std::swap(a, b);if (p) {if (b < t2) {break;}a += t2;b -= t2;ret = minus(ret, calc(a, b));} else {if (a < t1) {break;}a -= t1;b += t1;ret = plus(ret, calc(a, b));}}return ret;}ul sub[maxs + maxk + 2 + 1][maxs + maxk + 2 + 1];ul d[maxs + maxk + 2 + 1];ul e[maxs + maxk + 2 + 1];int main(){fac[0] = 1;for (ul i = 1; i <= maxn + maxm; ++i) {fac[i] = mul(fac[i - 1], i);}fiv[maxn + maxm] = inverse(fac[maxn + maxm]);for (ul i = maxn + maxm; i; --i) {fiv[i - 1] = mul(fiv[i], i);}std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u%u%u%u", &n, &m, &s, &k);for (ul i = k + 1; i <= k + s; ++i) {std::scanf("%u%u", &c[i].first, &c[i].second);e[i] = i;}for (ul i = 1; i <= k; ++i) {std::scanf("%u%u", &c[i].first, &c[i].second);e[i] = i;}c[k + s + 1] = std::pair<ul, ul>(1, 1);e[k + s + 1] = k + s + 1;c[k + s + 2] = std::pair<ul, ul>(n, m);e[k + s + 2] = k + s + 2;std::sort(e + 1, e + k + s + 2 + 1, [&](ul a, ul b){return c[a] < c[b];});for (ul i = 1; i <= k + s + 2; ++i) {for (ul j = 1; j <= k + s + 2; ++j) {if (c[i].first > c[j].first || c[i].second > c[j].second) {sub[i][j] = 0;} else {const auto& to = c[j];const auto& from = c[i];sub[i][j] = f(to.first - from.first, to.second - from.second, from.first - from.second + 1 + m - n, from.second - from.first + 1);}}}ul ans = 0;for (ul mask = (1 << k) - 1; ~mask; --mask) {tot = 0;for (ul i = 1; i <= k + s + 2; ++i) {if (e[i] >= k + 1 || (mask >> e[i] - 1 & 1)) {++tot;d[tot] = e[i];}}ul tans = 1;for (ul i = 1, j = 2; j <= tot; ++i, ++j) {if (sub[d[i]][d[j]] == 0) {tans = 0;break;}tans = mul(tans, sub[d[i]][d[j]]);}if (tot - s - 2 & 1) {ans = minus(ans, tans);} else {ans = plus(ans, tans);}}std::printf("Case #%u: %u\n", Case, ans);}return 0;}
参考https://www.zybuluo.com/qq290637843/note/1776933的情况一
#include <bits/stdc++.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;ul T;ul n;ul f(ul x, ul y, ul n){return x + y <= n - 1 ? x + y : x + y - n + 1;}ul g(ul x, ul n){return x + x <= n - 1 ? n - x : n + 1 - x;}int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u", &n);std::printf("Case #%u: %u\n", Case, n >> 1);if (n & 1) {for (ul i = 1; i <= (n >> 1); ++i) {std::printf("%u %u\n", n, f(1, i - 1, n));for (ul j = 1, gjm1 = 1; j <= n - 2; ++j, gjm1 = g(gjm1, n)) {std::printf("%u %u\n", f(gjm1, i - 1, n), f(g(gjm1, n), i - 1, n));}}} else {++n;for (ul i = 1; i <= (n >> 1); ++i) {for (ul j = 1, gjm1 = 1; j <= n - 2; ++j, gjm1 = g(gjm1, n)) {std::printf("%u %u\n", f(gjm1, i - 1, n), f(g(gjm1, n), i - 1, n));}}}}return 0;}
显然,能获得的边构成一棵树
#include <bits/stdc++.h>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, sr, sc, tr, tc;ul a, b, c, p;const ul maxn = 1e3;const ul maxm = 1e3;ul x[maxn * maxm + 1];ul fa[maxn * maxm + 1];ul rk[maxn * maxm + 1];std::vector<std::pair<ul, ul>> edges[10001];ul getfather(ul x){return x == fa[x] ? x : fa[x] = getfather(fa[x]);}bool connect(ul x, ul y){x = getfather(x);y = getfather(y);if (x == y) {return false;}if (rk[x] > rk[y]) {fa[y] = x;} else if (rk[y] > rk[x]) {fa[x] = y;} else {fa[y] = x;++rk[x];}return true;}int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u%u%u%u%u%u", &n, &m, &sr, &sc, &tr, &tc);std::scanf("%u%u%u%u%u%u", &x[1], &x[2], &a, &b, &c, &p);for (ul i = 0; i <= p * p; ++i) {edges[i].resize(0);}for (ul i = 3; i <= n * m; ++i) {x[i] = (a * x[i - 1] + b * x[i - 2] + c) % p;}for (ul i = 1; i <= n * m; ++i) {fa[i] = i;rk[i] = 0;}for (ul i = 1; i <= n; ++i) {for (ul j = 1; j <= m - 1; ++j) {ul s = (i - 1) * m + j;ul t = (i - 1) * m + j + 1;edges[x[s] * x[t]].push_back(std::pair<ul, ul>(s, t));}}for (ul i = 1; i <= n - 1; ++i) {for (ul j = 1; j <= m; ++j) {ul s = (i - 1) * m + j;ul t = i * m + j;edges[x[s] * x[t]].push_back(std::pair<ul, ul>(s, t));}}ull ans = 0;for (ul i = p * p; ~i; --i) {for (const auto& e : edges[i]) {ul s = e.first;ul t = e.second;if (connect(s, t)) {ans += i;}}}std::printf("Case #%u: %llu\n", Case, ans);}return 0;}
重链剖分线段树
#include <bits/stdc++.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul mod = 1e9 + 7;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;}ul T;ul n;const ul maxn = 1e5;std::vector<ul> edges[maxn + 1];ul dfn[maxn + 1];ul fa[maxn + 1];ul hvhd[maxn + 1];ul bigson[maxn + 1];ul depth[maxn + 1];void search1(ul curr, ul prev, ul& sz){sz = 1;ul bigsz = 0;for (ul next : edges[curr]) {if (next == prev) {continue;}depth[next] = depth[curr] + 1;fa[next] = curr;ul tsz;search1(next, curr, tsz);sz += tsz;if (tsz > bigsz) {bigson[curr] = next;bigsz = tsz;}}}ul tim;void search2(ul curr){++tim;dfn[curr] = tim;if (bigson[curr]) {hvhd[bigson[curr]] = hvhd[curr];search2(bigson[curr]);}for (ul next : edges[curr]) {if (next == fa[curr] || next == bigson[curr]) {continue;}hvhd[next] = next;search2(next);}}class node {public:ul sum[4];ul a = ~ul(0);ul b = ~ul(0);ul c = ~ul(0);};ul sz;const ul maxsz = 1 << 17;node tree[maxsz << 1];void combine(ul x, ul y){if (!~tree[x].a && !~tree[x].c) {return;}if (~tree[x].c) {tree[y].a = ~ul(0);tree[y].b = ~ul(0);tree[y].c = tree[x].c;} else if (~tree[y].a) {tree[y].b = plus(mul(tree[x].a, tree[y].b), tree[x].b);tree[y].a = mul(tree[x].a, tree[y].a);tree[y].c = ~ul(0);} else if (~tree[y].c) {tree[y].a = ~ul(0);tree[y].b = ~ul(0);tree[y].c = plus(mul(tree[x].a, tree[y].c), tree[x].b);} else {tree[y].a = tree[x].a;tree[y].b = tree[x].b;tree[y].c = tree[x].c;}}void push(ul x, bool down){if (~tree[x].a) {ul a = tree[x].a;ul a2 = mul(a, a);ul a3 = mul(a2, a);ul b = tree[x].b;ul b2 = mul(b, b);ul b3 = mul(b2, b);ul a2b = mul(a2, b);ul ab2 = mul(a, b2);ul ab = mul(a, b);tree[x].sum[3] = plus(plus(mul(a3, tree[x].sum[3]), mul(mul(3, a2b), tree[x].sum[2])), plus(mul(mul(3, ab2), tree[x].sum[1]), mul(b3, tree[x].sum[0])));tree[x].sum[2] = plus(plus(mul(a2, tree[x].sum[2]), mul(mul(2, ab), tree[x].sum[1])), mul(b2, tree[x].sum[0]));tree[x].sum[1] = plus(mul(a, tree[x].sum[1]), mul(b, tree[x].sum[0]));} else if (~tree[x].c) {ul c = tree[x].c;ul c2 = mul(c, c);ul c3 = mul(c2, c);tree[x].sum[3] = mul(c3, tree[x].sum[0]);tree[x].sum[2] = mul(c2, tree[x].sum[0]);tree[x].sum[1] = mul(c, tree[x].sum[0]);}if (down) {combine(x, x << 1);combine(x, x << 1 | 1);}tree[x].a = ~ul(0);tree[x].b = ~ul(0);tree[x].c = ~ul(0);}void change(ul l, ul r, ul nl, ul nr, ul nid, ul a, ul b, ul c){tree[nid].sum[0] = nr - nl + 1;push(nid, nl != nr);if (l <= nl && r >= nr) {tree[nid].a = a;tree[nid].b = b;tree[nid].c = c;push(nid, nl != nr);return;}ul midl = nl + nr >> 1;ul midr = midl + 1;if (l <= midl) {change(l, r, nl, midl, nid << 1, a, b, c);} else {tree[nid << 1].sum[0] = midl - nl + 1;push(nid << 1, nl != midl);}if (r >= midr) {change(l, r, midr, nr, nid << 1 | 1, a, b, c);} else {tree[nid << 1 | 1].sum[0] = nr - midr + 1;push(nid << 1 | 1, midr != nr);}for (ul i = 0; i <= 3; ++i) {tree[nid].sum[i] = plus(tree[nid << 1].sum[i], tree[nid << 1 | 1].sum[i]);}}ul query(ul l, ul r, ul nl, ul nr, ul nid){tree[nid].sum[0] = nr - nl + 1;push(nid, nl != nr);if (l <= nl && r >= nr) {return tree[nid].sum[3];}ul midl = nl + nr >> 1;ul midr = midl + 1;ul ret = 0;if (l <= midl) {ret = plus(ret, query(l, r, nl, midl, nid << 1));}if (r >= midr) {ret = plus(ret, query(l, r, midr, nr, nid << 1 | 1));}return ret;}ul q;int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u", &n);for (ul i = 1; i <= n; ++i) {bigson[i] = 0;edges[i].resize(0);}for (ul i = 1; i <= n - 1; ++i) {ul a, b;std::scanf("%u%u", &a, &b);edges[a].push_back(b);edges[b].push_back(a);}search1(1, 0, n);hvhd[1] = 1;tim = 0;search2(1);for (ul i = 1; i <= n; ++i) {ul w;std::scanf("%u", &w);change(dfn[i], dfn[i], 1, n, 1, ~ul(0), ~ul(0), w);}std::printf("Case #%u:\n", Case);std::scanf("%u", &q);for (ul i = 1; i <= q; ++i) {ul type;std::scanf("%u", &type);if (type != 4) {ul u, v, w;std::scanf("%u%u%u", &u, &v, &w);while (hvhd[u] != hvhd[v]) {if (depth[hvhd[u]] > depth[hvhd[v]]) {std::swap(u, v);}if (type == 1) {change(dfn[hvhd[v]], dfn[v], 1, n, 1, ~ul(0), ~ul(0), w);} else if (type == 2) {change(dfn[hvhd[v]], dfn[v], 1, n, 1, 1, w, ~ul(0));} else if (type == 3) {change(dfn[hvhd[v]], dfn[v], 1, n, 1, w, 0, ~ul(0));}v = fa[hvhd[v]];}if (depth[u] > depth[v]) {std::swap(u, v);}if (type == 1) {change(dfn[u], dfn[v], 1, n, 1, ~ul(0), ~ul(0), w);} else if (type == 2) {change(dfn[u], dfn[v], 1, n, 1, 1, w, ~ul(0));} else if (type == 3) {change(dfn[u], dfn[v], 1, n, 1, w, 0, ~ul(0));}} else {ul u, v;std::scanf("%u%u", &u, &v);ul ret = 0;while (hvhd[u] != hvhd[v]) {if (depth[hvhd[u]] > depth[hvhd[v]]) {std::swap(u, v);}ret = plus(ret, query(dfn[hvhd[v]], dfn[v], 1, n, 1));v = fa[hvhd[v]];}if (depth[u] > depth[v]) {std::swap(u, v);}ret = plus(ret, query(dfn[u], dfn[v], 1, n, 1));std::printf("%u\n", ret);}}}return 0;}
将所有合法方案作为点,如果两个点之间有重复牌就不连边,其余全部连边,于是变为最大团问题。
最大团算法见此https://chaoli.club/index.php/5052/
#include <bits/stdc++.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;ul T;ul n;std::map<std::string, std::pair<ul, ul>> strtov;const std::string name[4][3] = {{"one", "two", "three"}, {"diamond", "squiggle", "oval"}, {"solid", "striped", "open"}, {"red", "green", "purple"}};const ul maxn = 38;ul v[maxn + 1][4];char str[300];std::string tmp;ul tot;ul q[300][3];std::vector<ul> had[maxn + 1];using data = std::bitset<256>;data g[256];data ansr;data getfirst(const data& x){ul tmp = x._Find_next(0);data ret;ret[tmp] = 1;return ret;}ul first(const data& x){return x._Find_next(0);}bool flag = false;void bk(const data& r, data p, data x){if (!p.any() && !x.any()) {if (r.count() > ansr.count()) {ansr = r;if (r.count() == n / 3) {flag = true;}}return;}data px = p | x;data u = getfirst(px);for (data tu = getfirst(px); px.any(); px &= ~tu, tu = getfirst(px)) {if ((p & g[first(tu)]).count() > (p & g[first(u)]).count()) {u = tu;}}data ext = p & ~g[first(u)];for (data v = getfirst(ext); ext.any(); p &= ~v, x |= v, ext &= ~v, v = getfirst(ext)) {bk(r | v, p & g[first(v)], x & g[first(v)]);if (flag) {return;}}}int main(){for (ul i = 0; i != 4; ++i) {for (ul j = 0; j != 3; ++j) {strtov[name[i][j]] = std::pair<ul, ul>(i, j);}}std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u", &n);for (ul i = 1; i <= n; ++i) {had[i].resize(0);std::scanf("%s", str + 1);for (ul j = 1; str[j]; ++j) {if (str[j] == ']') {auto p = strtov[tmp];v[i][p.first] = p.second;tmp.resize(0);} else if (str[j] != '[') {tmp.push_back(str[j]);}}}tot = 0;for (ul a = 1; a + 2 <= n; ++a) {for (ul b = a + 1; b + 1 <= n; ++b) {for (ul c = b + 1; c <= n; ++c) {bool flag = true;for (ul i = 0; i != 4; ++i) {if ((v[a][i] + v[b][i] + v[c][i]) % 3) {flag = false;break;}}if (flag) {++tot;q[tot][0] = a;q[tot][1] = b;q[tot][2] = c;had[a].push_back(tot);had[b].push_back(tot);had[c].push_back(tot);}}}}for (ul i = 1; i <= tot; ++i) {g[i] = 0;for (ul j = 1; j <= tot; ++j) {if (i != j) {g[i][j] = 1;}}}for (ul a = 1; a <= n; ++a) {for (ul s = 0; s + 1 < had[a].size(); ++s) {for (ul t = s + 1; t < had[a].size(); ++t) {g[had[a][s]][had[a][t]] = 0;g[had[a][t]][had[a][s]] = 0;}}}ansr = 0;data all;for (ul i = 1; i <= tot; ++i) {all[i] = 1;}flag = false;bk(0, all, all);std::printf("Case #%u: %u\n", Case, ul(ansr.count()));for (ul i = 1; i <= tot; ++i) {if (ansr[i]) {std::printf("%u %u %u\n", q[i][0], q[i][1], q[i][2]);}}}return 0;}
二分贪心
#include <bits/stdc++.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;ul T;ul n;ul k;const ul maxn = 1e5;ul w[maxn + 1];std::vector<ul> edges[maxn + 1];std::vector<ull> stack[maxn + 1];void search(ul curr, ul prev, ull bound, ul& cnt, ull& sum){stack[curr].resize(0);cnt = 0;for (ul next : edges[curr]) {if (next == prev) {continue;}stack[curr].push_back(0);ul tcnt;search(next, curr, bound, tcnt, stack[curr].back());cnt += tcnt;}std::sort(stack[curr].begin(), stack[curr].end());sum = w[curr];for (ul i = 0; i != stack[curr].size(); ++i) {if (sum + stack[curr][i] > bound) {cnt += stack[curr].size() - i;break;}sum += stack[curr][i];}}int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u%u", &n, &k);for (ul i = 1; i <= n; ++i) {edges[i].resize(0);}ull mx = 0;for (ul i = 1; i <= n - 1; ++i) {ul u, v;std::scanf("%u%u", &u, &v);edges[u].push_back(v);edges[v].push_back(u);}for (ul i = 1; i <= n; ++i) {std::scanf("%u", &w[i]);mx = std::max(mx, ull(w[i]));}ull l = mx - 1, r = 1e14;while (l + 1 != r) {ull mid = l + r >> 1;ul cnt;ull s;search(1, 0, mid, cnt, s);if (cnt >= k) {l = mid;} else {r = mid;}}std::printf("Case #%u: %llu\n", Case, r);}return 0;}
首先将原问题重新叙述如下:
有一个长方形,有两个点,对于中的两点和,定义两点的距离为
猜想的证明如下:
首先证明:对任何中的紧凸集,如果紧凸集()的并能覆盖的边界,那就能覆盖。
考虑有一点没有被覆盖,将此点记为,考虑从到分别最近的点,连线段,分别过作线段的垂直超平面。而显然,中是不可能用少于或等于个超平面围出一个有界区域的,于是可知这些超平面围不出一个有界区域,从而有一个方向能不经过到达的边界,故的边界没有被覆盖,矛盾。
于是考虑有个紧凸集覆盖了某平直边界紧凸集的所有维边界,根据上方命题可知,维部分全被覆盖。
#include <bits/stdc++.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;using llf = long double;class vec {public:llf x = 0;llf y = 0;vec()=default;vec(llf a, llf b): x(a), y(b) {}};vec operator+(const vec& a, const vec& b){return vec(a.x + b.x, a.y + b.y);}vec operator-(const vec& a, const vec& b){return vec(a.x - b.x, a.y - b.y);}llf operator*(const vec& a, const vec& b){return a.x * b.x + a.y * b.y;}vec operator*(llf a, const vec& b){return vec(a * b.x, a * b.y);}vec operator*(const vec& a, llf b){return vec(a.x * b, a.y * b);}vec operator/(const vec& a, llf b){return vec(a.x / b, a.y / b);}llf len2(const vec& a, const vec& b){return (a - b) * (a - b);}llf len(const vec& a, const vec& b){return std::sqrt((a - b) * (a - b));}vec p1, p2;llf dis(const vec& a, const vec& b){return std::min(len(a, b), std::min(len(a, p1) + len(p2, b), len(a, p2) + len(p1, b)));}vec cs[5];vec rotate(const vec& a){return vec(-a.y, a.x);}bool calc(llf a, llf b, llf c, llf& t1, llf& t2){if (a < 1e-5 && a > -1e-5) {t1 = -c / b;t2 = -c / b;return true;}llf delta = b * b - llf(4) * a * c;if (delta < 0) {return false;}t1 = (-b - std::sqrt(delta)) / a * llf(0.5);t2 = (-b + std::sqrt(delta)) / a * llf(0.5);return true;}llf calc(const vec& start, vec& ans){llf ret = 0;vec o, xdir, ydir;llf a, b;if (len2(p1, start) < len2(p2, start)) {a = len(start, p1) * llf(0.5);b = std::sqrt(len2(start, p2) - len2(start, p1)) * llf(0.5);o = (start + p2) * llf(0.5);xdir = (p2 - start) / len(p2, start);ydir = rotate(xdir);} else if (len2(p2, start) < len2(p1, start)) {a = len(start, p2) * llf(0.5);b = std::sqrt(len2(start, p1) - len2(start, p2)) * llf(0.5);o = (start + p1) * llf(0.5);xdir = (p1 - start) / len(p1, start);ydir = rotate(xdir);} else {for (ul i = 1; i <= 4; ++i) {llf tmp = dis(start, cs[i]);if (ret < tmp) {ans = cs[i];ret = tmp;}}return ret;}for (ul i = 1; i <= 4; ++i) {vec alpha = vec((cs[i - 1] - o) * xdir, (cs[i - 1] - o) * ydir);vec beta = vec((cs[i] - o) * xdir, (cs[i] - o) * ydir);llf tmp = dis(start, cs[i]);if (ret < tmp) {ans = cs[i];ret = tmp;}llf t1, t2;bool flag = calc(b * b * (alpha.x - beta.x) * (alpha.x - beta.x) - a * a * (alpha.y - beta.y) * (alpha.y - beta.y), 2 * (alpha.x * b * b * (beta.x - alpha.x) + a * a * alpha.y * (alpha.y - beta.y)), alpha.x * alpha.x * b * b - a * a * alpha.y * alpha.y - a * a * b * b, t1, t2);if (flag) {if (t1 >= 0 && t1 <= 1) {vec k = cs[i - 1] + t1 * (cs[i] - cs[i - 1]);llf tmp = dis(start, k);if (ret < tmp) {ans = k;ret = tmp;}}if (t2 >= 0 && t2 <= 1) {vec k = cs[i - 1] + t2 * (cs[i] - cs[i - 1]);llf tmp = dis(start, k);if (ret < tmp) {ans = k;ret = tmp;}}}}return ret;}ul T;int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {ul a, b, x1, x2, y1, y2;std::scanf("%u%u%u%u%u%u", &a, &b, &x1, &y1, &x2, &y2);p1 = vec(x1, y1);p2 = vec(x2, y2);cs[1] = vec(0, 0);cs[2] = vec(a, 0);cs[3] = vec(a, b);cs[4] = vec(0, b);cs[0] = cs[4];llf ans = 0;vec out1, out2;for (ul i = 1; i <= 4; ++i) {llf tans;vec tout2;tans = calc(cs[i], tout2);if (tans > ans) {ans = tans;out1 = cs[i];out2 = tout2;}}std::printf("Case #%u:\n", Case);std::printf("%.20Lf %.20Lf\n%.20Lf %.20Lf\n", out1.x, out1.y, out2.x, out2.y);}return 0;}
直接看代码
#include <bits/stdc++.h>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 maxn = 1e4;const ul maxm = 1e4;class node {public:ul son[10];ull sum = 0;node() {std::memset(son, 0, sizeof(son));}};ul tot;node tree[maxn * 10 + maxm * 10 + 2];ul stack[maxn * 10 + maxm * 10 + 2];ul remain;ul newnode(){ul tmp;if (remain) {tmp = stack[remain];--remain;} else {++tot;tmp = tot;}tree[tmp] = node();return tmp;}void kill(ul& x){++remain;stack[remain] = x;x = 0;}ull plus(ull a, ull b){ull c = 0;ull i = 1;while (a || b) {ull k = (a % 10 + b % 10) % 10;c += k * i;a /= 10;b /= 10;i *= 10;}return c;}void add(ull x, ul root){static ul ins[10];ull xx = x;for (ul i = 0; i <= 9; ++i) {ins[i] = x % 10;x /= 10;}x = xx;ul curr = root;for (ul i = 9; ~i; --i) {if (!tree[curr].son[ins[i]]) {tree[curr].son[ins[i]] = newnode();}curr = tree[curr].son[ins[i]];tree[curr].sum = plus(tree[curr].sum, x);}}void shift(ul& root){for (ul i = 0; i <= 9; ++i) {if (tree[root].son[i]) {tree[root].sum = plus(tree[root].sum, tree[tree[root].son[i]].sum);}}ul s = root;root = newnode();tree[root].son[0] = s;using pulul = std::pair<ul, ul>;static pulul stack[maxn * 10 + maxm * 10 + 2];ul tot = 0;++tot;stack[tot] = pulul(s, 9);while (tot) {auto curr = stack[tot].first;auto index = stack[tot].second;--tot;tree[curr].sum /= 10;for (ul i = 0; i != 10; ++i) {if (tree[curr].son[i]) {if (index == 0) {kill(tree[curr].son[i]);} else {++tot;stack[tot].first = tree[curr].son[i];stack[tot].second = index - 1;}}}}}ull query(ull x, ul root){static ul ins[10];for (ul i = 0; i <= 9; ++i) {ins[i] = x % 10;x /= 10;}ul curr = root;ull ret2 = 0;for (ul i = 9; ~i; --i) {for (ul j = 9; ~j; --j) {ul t = j < ins[i] ? j + 10 - ins[i] : j - ins[i];if (tree[curr].son[t]) {ret2 *= 10;ret2 += j;curr = tree[curr].son[t];break;}}}return ret2;}ull sum(ull l, ull r, ul nid, ull nl, ull nr){if (l <= nl && r >= nr) {return tree[nid].sum;}ull ret = 0;ull part = (nr - nl + 1) / 10;for (ull i = 0, ml = nl, mr = nl + part - 1; i <= 9; ++i, ml += part, mr += part) {if (!tree[nid].son[i]) {continue;}if (l <= mr && r >= ml) {ret = plus(ret, sum(l, r, tree[nid].son[i], ml, mr));}}return ret;}char str[100];int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::printf("Case #%u:\n", Case);std::scanf("%u%u", &n, &m);tot = 0;remain = 0;ul root = newnode();for (ul i = 1; i <= n; ++i) {ull a;std::scanf("%llu", &a);add(a, root);}for (ul i = 1; i <= m; ++i) {std::scanf("%s", str + 1);if (std::strcmp(str + 1, "Add") == 0) {ull a;std::scanf("%llu", &a);add(a, root);} else if (std::strcmp(str + 1, "Query") == 0) {ull a;std::scanf("%llu", &a);std::printf("%llu\n", query(a, root));} else if (std::strcmp(str + 1, "Shift") == 0) {shift(root);} else if (std::strcmp(str + 1, "Sum") == 0) {ull l, r;std::scanf("%llu%llu", &l, &r);std::printf("%llu\n", sum(l, r, root, 0, 9999999999ull));}}}return 0;}
简单题
#include <bits/stdc++.h>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 maxn = 16;ul g(ul x){return x ^ x >> 1;}ul edges[maxn + 1];int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u%u", &n, &m);for (ul i = 1; i <= n; ++i) {edges[i] = 0;}for (ul i = 1; i <= m; ++i) {ul u, v;std::scanf("%u%u", &u, &v);edges[u] |= 1 << v - 1;edges[v] |= 1 << u - 1;}ul ans = 0;ul tmp = 0;for (ul i = 1; i != (1 << n); ++i) {ul curr = g(i);ul prev = g(i - 1);ul id = __builtin_ctz(curr ^ prev) + 1;tmp -= __builtin_popcount(edges[id] & ((prev >> id - 1 & 1) ? ~prev : prev));tmp += __builtin_popcount(edges[id] & ((curr >> id - 1 & 1) ? ~curr : curr));ans = std::max(tmp, ans);}std::printf("Case #%u: %u\n", Case, ans);}return 0;}
狄克斯特拉费用流,注意由于是稠密图,不要用堆优化。
#include <bits/stdc++.h>using ul = std::uint32_t;using li = std::int32_t;using ull = std::uint64_t;using ll = std::int64_t;const ul maxn = 600;const ul maxm = maxn + 1;const li liinf = (li(1) << 31) - 1;const ll llinf = (ll(1) << 63) - 1;class mcmf {public:class edge_t {public:ul to = 0;li cap = 0;li cost = 0;edge_t()=default;edge_t(ul to, li cap, li cost): to(to), cap(cap), cost(cost) {}};class node_t {public:ll pi;ll sigma;ul p;li a;ul vis;std::vector<ul> edge;};edge_t edge[maxm + maxm + maxm * maxm << 1];node_t node[maxm + maxm + 2];std::vector<ul> stack;bool instack[maxm + maxm + maxm * maxm << 1];std::queue<ul> queue;ul tim = 0;ul n, m;void init(ul n) {this->n = n;for (ul i = 0; i != n; ++i) {node[i].edge.resize(0);node[i].pi = 0;}std::memset(instack, false, sizeof(bool) * n);stack.resize(0);m = 0;}void addedge(ul from, ul to, li cap, li cost) {edge[m] = edge_t(to, cap, cost);++m;edge[m] = edge_t(from, 0, -cost);++m;node[from].edge.push_back(m - 2);node[to].edge.push_back(m - 1);}bool dikstra(ul s, ul t, li& flow, ll& cost) {for (ul i = 0; i != n; ++i) {node[i].sigma = llinf;}node[s].sigma = 0;stack.push_back(s);instack[s] = true;while (stack.size()) {ul small = 0;for (ul i = 0; i != stack.size(); ++i) {if (node[stack[i]].sigma < node[stack[small]].sigma) {small = i;}}std::swap(stack[small], stack.back());ul curr = stack.back();stack.pop_back();instack[curr] = false;for (ul i : node[curr].edge) {edge_t& e = edge[i];if (e.cap > 0 && node[e.to].sigma > node[curr].sigma + e.cost + node[curr].pi - node[e.to].pi) {node[e.to].sigma = node[curr].sigma + e.cost + node[curr].pi - node[e.to].pi;if (!instack[e.to]) {stack.push_back(e.to);instack[e.to] = true;}}}}if (node[t].sigma == llinf) {return false;}while (queue.size()) {queue.pop();}++tim;node[s].p = -1;node[s].a = liinf;queue.push(s);node[s].vis = tim;while (queue.size()) {ul curr = queue.front();queue.pop();for (ul i : node[curr].edge) {edge_t& e = edge[i];ul nex = e.to;if (e.cap > 0 && node[nex].vis != tim && node[nex].sigma == node[curr].sigma + e.cost + node[curr].pi - node[nex].pi) {node[nex].p = i;node[nex].a = std::min(node[curr].a, e.cap);node[nex].vis = tim;queue.push(nex);}}}flow += node[t].a;cost += ll(node[t].sigma + node[t].pi - node[s].pi) * node[t].a;ul u = t;while (u != s) {edge[node[u].p].cap -= node[t].a;edge[node[u].p ^ 1].cap += node[t].a;u = edge[node[u].p ^ 1].to;}for (ul i = 0; i != n; ++i) {node[i].pi = node[i].sigma == llinf ? llinf : node[i].pi + node[i].sigma;}return true;}ll mincost(ul s, ul t) {li flow = 0;ll cost = 0;while (dikstra(s, t, flow, cost));return cost;}};mcmf graph;ul T;ul n, m;ll a[maxn + 1];ll b[maxm + 1];int main(){std::scanf("%u", &T);for (ul Case = 1; Case <= T; ++Case) {std::scanf("%u%u", &n, &m);for (ul i = 1; i <= n; ++i) {std::scanf("%lld", &a[i]);}for (ul i = 1; i <= m; ++i) {std::scanf("%lld", &b[i]);}ll ans = 0;for (ul i = 2; i <= n; ++i) {ans += std::max(a[i], a[i - 1]) - std::min(a[i], a[i - 1]);}graph.init(2 + n + 1 + m);for (ul i = 1; i <= n + 1; ++i) {graph.addedge(0, i, 1, 0);}for (ul j = n + 1 + 1; j <= n + 1 + m; ++j) {graph.addedge(j, n + 1 + m + 1, 1, 0);}for (ul i = 1; i <= n + 1; ++i) {for (ul j = 1; j <= m; ++j) {ll alpha = 0;ll beta = 0;if (i != 1) {alpha += std::max(b[j], a[i - 1]) - std::min(b[j], a[i - 1]);}if (i != n + 1) {alpha += std::max(b[j], a[i]) - std::min(b[j], a[i]);}if (i != 1 && i != n + 1) {beta = std::max(a[i], a[i - 1]) - std::min(a[i], a[i - 1]);}graph.addedge(i, n + 1 + j, 1, beta - alpha);}}std::printf("Case #%u:\n", Case);li flow = 0;ll cost = 0;for (ul i = 1; i <= m; ++i) {if (i != 1) {std::putchar(' ');}graph.dikstra(0, n + 1 + m + 1, flow, cost);std::printf("%lld", ans - cost);}std::putchar('\n');bool flag = false;for (ul i = 1; i <= n + 1; ++i) {for (ul eid : graph.node[i].edge) {const auto& e = graph.edge[eid];if (!e.cap && e.to >= n + 1 + 1) {ul j = e.to - n - 1;if (flag) {std::putchar(' ');}std::printf("%lld", b[j]);flag = true;break;}}if (i != n + 1) {if (flag) {std::putchar(' ');}std::printf("%lld", a[i]);flag = true;}}std::putchar('\n');}return 0;}