[题解]膜游赛
\(\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)\),那么,如果仅考虑操作一,我们就可以将答案写成
其中满足 \(\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\),我们可以分别在左边,右边找到这样的点各一个:
- 从该点 \(p\) 开始的回文串覆盖了 \(c_i\) 位置;
- 满足 \(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;
}