[题解]膜游赛

\[\color{red}{\text{校长者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?}} \\ \begin{array}{|} \hline \color{pink}{\text{The principal is really a god}} \\ \color{pink}{\text{with a closestool on the left and Yongshen on the right}} \\ \color{pink}{\text{holding a sharp pen to pierce the truth}} \\ \color{pink}{\text{Who can resist him? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{green}{\text{校長は本当に神であり、左側にトイレ、右側にヨンシェンがあり}} \\ \color{green}{\text{鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{lightblue}{\text{Le principal est vraiment un dieu}} \\ \color{lightblue}{\text{avec des toilettes à gauche et Yongshen à droite}} \\ \color{lightblue}{\text{tenant un stylo pointu pour percer la vérité}} \\ \color{lightblue}{\text{Qui peut lui résister ? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{purple}{\text{Der Direktor ist wirklich ein Gott}} \\ \color{purple}{\text{mit einer Toilette links und Yongshen rechts}} \\ \color{purple}{\text{der einen spitzen Stift hält}} \\ \color{purple}{\text{um die Wahrheit zu durchdringen.}} \\ \color{purple}{\text{Wer kann ihm widerstehen? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{cyan}{\text{Principalis deus est, Yongshen a dextris cum latrina}} \\ \color{cyan}{\text{acuto stylo ad perforandum veritatem: quis resistet ei? }} \\ \hline \end{array} \\ \color{red}{\text{对曰:“无人,狗欲当之,还请赐教!”}} \\ \newcommand\brak[1]{\left({#1}\right)} \newcommand\Brak[1]{\left\{{#1}\right\}} \newcommand\d[0]{\text{d}} \newcommand\string[2]{\genfrac{\{}{\}}{0pt}{}{#1}{#2}} \newcommand\down[2]{{#1}^{\underline{#2}}} \newcommand\ddiv[2]{\left\lfloor\frac{#1}{#2}\right\rfloor} \newcommand\udiv[2]{\left\lceil\frac{#1}{#2}\right\rceil} \newcommand\lcm[0]{\operatorname{lcm}} \newcommand\set[1]{\left\{{#1}\right\}} \newcommand\ceil[1]{\left\lceil{#1}\right\rceil} \newcommand\floor[1]{\left\lfloor{#1}\right\rfloor} \newcommand\rhs[1]{\;\text{Rhs}\;#1} \newcommand\lhs[1]{\;\text{Lhs}\;#1} \newcommand\Vec[1]{\vec{\mathbf{#1}}} \newcommand\rank[0]{\text{rank}} \]




  \(\mathcal{Back\;To\;The\;Menu}\).

2022-01-23 膜游赛

力争大游 / Merge

  注意到 \(\displaystyle \ddiv{x}{2}\) 相当于 \(x\rhs 1\),并且 \((x\cup y)\rhs 1=(x\rhs 1)\cup(y\rhs 1)\),那么,如果仅考虑操作一,我们就可以将答案写成

\[\bigcup_{i=1}^n(a_i\rhs d_i) \]

  其中满足 \(\displaystyle \sum_{i=1}^n\frac{1}{2^{d_i}}=1\).

  现在的问题是,出现删除操作之后应该怎么办?由于删除操作相当于减去某些 \(\displaystyle \frac{1}{2^{d_i}}\),所以我们应当让 \(\displaystyle \sum_{i=1}^n\frac{1}{2^{d_i}}\ge 1\),并且此刻一定存在一个子集 \(\displaystyle S\;\text{s.t.}\;\sum_{i\in S}\frac{1}{2^{d_i}}=1\),此时,我们将不属于 \(S\) 的东西删去,将会获得更小的答案(因为或上一个数一定不会变小)。同样的道理,如果存在某两种方案,他们的合并结果是一样的,那么 \(\displaystyle \sum_{i\in S}\frac{1}{2^{d_i}}=1\) 更大的将更有可能成为答案,换而言之,我们想要让每个 \(d_i\) 尽可能的小。

  当然,我们可以设计 \(\rm DP\) 进行转移,转移也比较简单,不过我们需要记录当前的合并结果,这使得状态极其庞大,时间复杂度也达到 \(\mathcal O(Tw2^w)\) 级别。应当另辟蹊径。

  不难发现,假设我们现在已有一个答案 \(T\),那么应当满足 \(\forall i\in S,\overline T\in \overline{a_i\rhs d_i}\),即 \(T\)\(0\) 的位数,所有 \(a_i\rhs d_i\) 对应也应当为 \(0\). 那么我们可以假设答案全为 \(1\),此刻限制最松,然后依次确定 \(0\) 位,由于我们要使得答案最大,所以从高往低确定,检测一位是否为 \(0\) 时,对于每个数找到最小的 \(d_i\),然后检测 \(\displaystyle \sum_{i=1}^n\frac{1}{2^{d_i}}\overset?\ge 1\) 即可。

  枚举答案的每一位是 \(\mathcal O(w)\),每一轮检测是 \(\mathcal O(nw)\) 的,总复杂度 \(\mathcal O(Tnw^2)\),但是我们可以通过某些位运算的方法略去一个 \(w\). 假设每个 \(0\) 的限制相邻的距离为 \(t_1,t_2\cdots\),那么我们找到 \(\displaystyle\bigcup_{j}(a_i\lhs t_j)\) 的最低位 \(0\) 即可,左移实际上是将多个限制叠到一个位置上去,我们只需要找到这一个位置即可。最后的复杂度为 \(\mathcal O(Tnw)\).

/** @author Arextre */

#include <bits/stdc++.h>

#define USING_FREAD
// #define NDEBUG
// #define NCHECK
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#ifdef NCHECK
# define iputs(Content) ((void)0)
# define iprintf(Content, argvs...) ((void)0)
#else
# define iputs(Content) fprintf(stderr, Content)
# define iprintf(Content, argvs...) fprintf(stderr, Content, argvs)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void getmin(T& x, const T rhs) { x = min(x, rhs); }
template<class T> inline void getmax(T& x, const T rhs) { x = max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int maxn = 1e5;
const int maxw = 60;

ll a[maxn + 5]; int n, w;
ll valid[maxn + 5], tmp[maxn + 5];

signed main() {
    freopen("merge.in", "r", stdin);
    freopen("merge.out", "w", stdout);
    int T; readin(T);
    while (T--) {
        readin(n, w);
        rep (i, 1, n) readin(a[i]);
        std::sort(a + 1, a + n + 1);
        if (a[1] == 0) return writln(0), 0;
        ll ans = (1ll << w) - 1;
        rep (i, 1, n) valid[i] = (1ll << w + 1) - 1;
        for (int b = w - 1; ~b; --b) {
            int cnt[maxw + 5] = {};
            rep (i, 1, n) tmp[i] = valid[i] & (~(a[i] >> b));
            rep (i, 1, n) ++cnt[__builtin_ffsll(tmp[i]) - 1];
            int res = 0;
            for (int i = w; ~i; --i) res = (res >> 1) + cnt[i];
            if (res) ans ^= 1ll << b, memcpy(valid + 1, tmp + 1, n << 3);
        }
        writln(ans);
    }
    return 0;
}

击水中游 / Pass

  如果一个询问 \([ql_i,qr_i]\) 之中存在形如 aba 的子串,那么直接输出 \(1\) 了。否则,我们不难说明剩下的情形中,只有可能是偶数长度的回文串的覆盖。接下来所有的回文串,除特殊说明,均指偶长回文串。

  先用一个 \(\texttt{manacher}\) 跑出极长回文串,一个询问是成功的,当且仅当该子串每个点都被至少一个回文串覆盖。要从原串中提取一个子串出来找回文串很复杂,我们考虑从单个字符反过来刻画整个询问的合法性。考虑一个字符的合法情况是什么样子的:对于一个字符 \(c_i\),我们可以分别在左边,右边找到这样的点各一个:

  1. 从该点 \(p\) 开始的回文串覆盖了 \(c_i\) 位置;
  2. 满足 \(1\) 条件的最近的 \(p\)

  然后,我们可以在左边和右边对于这个点作对称,得到 \(l_i,r_i\),如果某个询问 \([ql,qr]\) 包含了 \(l_i,r_i\) 中的任意一个,则说明 \(c_i\) 被回文串覆盖,由于有 “或” 的因素在其中,我们反过来考虑 —— 一个询问 \([ql,qr]\) 不合法,当且仅当 \(\exists i\in [ql_i,qr_i], l_i<ql_i\land qr_i<r_i\Leftrightarrow \exists i\;\text{s.t.}\;l_i<ql\le i\le qr<r_i\),对于这个东西,扫描线解决 \(l_i<ql\) 的部分,剩下的两个限制 \(ql\le i\le qr\) 以及 \(qr<r_i\) 就是二维偏序的东西了,一发线段树搞定。

/** @author Arextre */

#include <bits/stdc++.h>

#define USING_FREAD
// #define NDEBUG
// #define NCHECK
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#ifdef NCHECK
# define iputs(Content) ((void)0)
# define iprintf(Content, argvs...) ((void)0)
#else
# define iputs(Content) fprintf(stderr, Content)
# define iprintf(Content, argvs...) fprintf(stderr, Content, argvs)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void getmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void getmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int maxn = 1e6 * 2;

int n;
char a[maxn + 5], s[maxn + 5];

inline void input() {
    std::cin >> n >> a + 1;
    *s = '$';
    rep (i, 1, n) s[(i - 1) << 1 | 1] = '#', s[i << 1] = a[i];
    s[n << 1 | 1] = '&';
}

int len[maxn + 5], pre[maxn + 5];
inline void manacher() {
    int p = 0, r = -1;
    rep (i, 1, n << 1) {
        // fprintf(stderr, "i == %d\n", i);
        if (r < i) {
            p = i, r = -1;
            while (s[i - len[i] - 1] == s[i + len[i] + 1]) ++len[i];
            r = i + len[i];
        }
        else {
            len[i] = len[(p << 1) - i];
            if (i + len[i] >= r) {
                p = i, len[i] = r - i;
                while (s[i - len[i] - 1] == s[i + len[i] + 1]) ++len[i];
                r = i + len[i];
            }
        }
        if (!(i & 1) && len[i] >= 2) ++pre[i >> 1];
        if (i % 100000 == 0) fprintf(stderr, "finished i == %d\n", i);
    }
    rep (i, 1, n) pre[i] += pre[i - 1];

}

int l[maxn + 5], r[maxn + 5];
inline void prelude() {
    int stk[maxn + 5], ed = 0;
    rep (i, 1, n << 1) {
        if (!(i & 1)) { // a character
            while (ed && stk[ed] + len[stk[ed]] < i) --ed;
            if (ed) l[i >> 1] = ((stk[ed] << 1) - i) >> 1;
            else l[i >> 1] = 0;
        }
        else { // a block
            while (ed && stk[ed] + len[stk[ed]] < i + len[i]) --ed;
            stk[++ed] = i;
        }
    }
    ed = 0;
    drep (i, n << 1, 1) { // reverse, again
        if (!(i & 1)) {
            while (ed && stk[ed] - len[stk[ed]] > i) --ed;
            if (ed) r[i >> 1] = ((stk[ed] << 1) - i) >> 1;
            else r[i >> 1] = n + 1;
        }
        else {
            while (ed && stk[ed] - len[stk[ed]] > i - len[i]) --ed;
            stk[++ed] = i;
        }
    }
}

int q, ql[maxn + 5], qr[maxn + 5];
bool ans[maxn + 5];
std::vector<int> v[maxn + 5];
inline void getQuery() {
    std::cin >> q;
    rep (i, 1, q) {
        std::cin >> ql[i] >> qr[i];
        if (ql[i] == qr[i]) ans[i] = false;
        else if (ql[i] + 1 == qr[i]) ans[i] = (a[ql[i]] == a[qr[i]]);
        else if (pre[qr[i] - 1] - pre[ql[i]]) ans[i] = true;
        else v[ql[i]].push_back(i);
    }
}

std::vector<pii> req[maxn + 5];
namespace saya {

int mx[maxn << 2 | 2];

#define ls (i << 1)
#define rs (i << 1 | 1)
#define mid ((l + r) >> 1)
#define _lhs ls, l, mid
#define _rhs rs, mid + 1, r

inline void pushup(int i) { mx[i] = std::max(mx[ls], mx[rs]); }

inline void insert(int p, int v, int i = 1, int l = 1, int r = n) {
    if (l == r) return mx[i] = v, void();
    if (p <= mid) insert(p, v, _lhs);
    else insert(p, v, _rhs);
    pushup(i);
}

inline int query(int ql, int qr, int i = 1, int l = 1, int r = n) {
    // fprintf(stderr, "l == %d, r == %d", l, r);
    if (ql <= l && r <= qr) return mx[i];
    int ret = 0;
    if (ql <= mid) ret = query(ql, qr, _lhs);
    if (mid < qr) getmax(ret, query(ql, qr, _rhs));
    return ret;
}

#undef ls
#undef rs
#undef mid
#undef _lhs
#undef _rhs

} // namespace saya;
inline void solve() {
    rep (i, 1, n) req[l[i]].push_back({ i, r[i] });
    rep (i, 0, n) {
        for (int j = 0, sz = req[i].size(); j < sz; ++j)
            saya::insert(req[i][j].fi, req[i][j].se);
        for (int j = 0, sz = v[i + 1].size(), p, mxx; j < sz; ++j) {
            p = v[i + 1][j];
            mxx = saya::query(i + 1, qr[p]);
            if (qr[p] < mxx) ans[p] = false;
            else ans[p] = true;
        }
    }
}

inline void print() {
    rep (i, 1, q) printf("%d", (int)(ans[i])); Endl;
}

signed main() {
    freopen("pass.in", "r", stdin);
    freopen("pass.out", "w", stdout);
    std::cin.tie(NULL)->sync_with_stdio(false);
    input();
    fprintf(stderr, "input!\n");
    manacher();
    fprintf(stderr, "first!\n");
    prelude();
    fprintf(stderr, "second!\n");
    getQuery();
    fprintf(stderr, "third!\n");
    solve();
    print();
    return 0;
}

膜拜小游 / Worship

  注意到最优情况一定会全部是二元环,考虑如何证明:假设存在环 \(A_1\to B_1\to A_2\to B_2\to A_1\),不妨设 \(A_1\le A_2\),那么,既然 \(B_1\) 都可以到 \(A_2\) 了,那么它为什么不直接回到 \(A_1\) 而还要去浪费 \(A_2\) 一次机会?

  然后贪心匹配就行了,将 \(A\) 映射为 \((i,a_i)\)\(B\) 映射为 \((b_j,j)\),用 \(set\) 动态维护即可。

/** @author Arextre */

#include <bits/stdc++.h>

#define USING_FREAD
// #define NDEBUG
// #define NCHECK
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#ifdef NCHECK
# define iputs(Content) ((void)0)
# define iprintf(Content, argvs...) ((void)0)
#else
# define iputs(Content) fprintf(stderr, Content)
# define iprintf(Content, argvs...) fprintf(stderr, Content, argvs)
#endif

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void getmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void getmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int maxn = 5e5;

pii a[maxn + 5];
int b[maxn + 5], c[maxn + 5], d[maxn + 5], n, m;

signed main() {
    freopen("worship.in", "r", stdin);
    freopen("worship.out", "w", stdout);
    readin(n, m);
    rep (i, 1, n) readin(a[i].fi), a[i].se = i;
    rep (i, 1, m) readin(b[i]);
    rep (i, 1, n) readin(c[i]);
    rep (i, 1, m) readin(d[i]);
    sort(a + 1, a + 1 + n);
    int id = 1; ll ans = 0;
    std::set<pii> S;
    rep (i, 1, n) {
        while (id <= m && id <= a[i].fi) {
            S.insert({ b[id], id }); ++id;
        }
        while (c[a[i].se]) {
            auto it = S.lower_bound({ a[i].se, 0 });
            if (it == S.end()) break;
            ans += std::min(c[a[i].se], d[it->second]);
            if (c[a[i].se] >= d[it->second])
                c[a[i].se] -= d[it->second], S.erase(it);
            else d[it->second] -= c[a[i].se], c[a[i].se] = 0;
        }
    }
    writln(ans);
    return 0;
}
posted @ 2022-03-14 21:43  Arextre  阅读(59)  评论(0编辑  收藏  举报