闲话 22.11.11

闲话

好多人发lg博客当做犇犇
我不知道为什么
我不干这活

image
……您?

很早以前(?)就想说了
lg 提交 2.24k 通过 428
所以我的通过率是 19%
这该算是你谷倒50的能力吧

最近在做这题
但是暴力都写不出来(
什么时候再给一天复习时间大概就有新社论了(坑)

?今天双十一?

杂题

[CERC2016]机棚障碍

你正在评估一些关于一个巨型飞机仓库的建设计划。飞机仓库的地面可以表示为 \(n\)\(n\) 列的网格图,其中每个格子要么是空的,要么有障碍物。行从上到下依次被编号为 \(1\)\(n\),列从左到右依次被编号为 \(1\)\(n\)

存放飞机零件的大型集装箱能在飞机仓库的地面上自由移动是很重要的。我们可以将每个集装箱看作一个以某个格子为中心的边平行于坐标轴的正方形。对于一个奇数 \(k\),一个尺寸为 \(k\) 的集装箱是一个包含 \(k\)\(k\) 列的正方形。一个集装箱的坐标为其中心格子的坐标。集装箱可以向上下左右移动,但不能碰到障碍物,且不能移出仓库的边界。

给定 \(q\) 对格子 \(A_k\)\(B_k\),对于每对格子,请找到能从 \(A_k\) 移动到 \(B_k\) 的集装箱的最大尺寸,注意这个尺寸也要是一个奇数。

\(2\le n \le 1000, 1\le q \le 3\times 10^5\)

比较水。

首先二分出每个点作为中心时最大能放的范围。\(O(n^2 \log n)\)
然后在每两个点间建边,使用 Kruskal 最大重构树即可求得任意两点间最大瓶颈路。

注意求 lca 不要像某个nt用 \(O(1)\) LCA 因为复杂度是假的
树剖 LCA 即可。

code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using db = double;
using ld = long double;
using lll = __int128_t;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
#define rep(i, s, t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++i)
#define pre(i, s, t) for (register int i = (s), i##_ = (t)-1; i > i##_; --i)
const int N = 1e3 + 100;
// const int B = 300;

// const int mod = 469762049, g = 3;
// const int mod = 998244353, g = 3;
// const int mod = 1004535809, g = 3;
// const int mod = 1e9 + 7;
// const int mod = 1e9 + 9;
// const int mod = 1e9 + 3579, bse = 131;
// const int inv2 = (mod + 1) >> 1;
// template <typename T1, typename T2> T1 add(T1 a, T2 b) { return (a += b) >= mod ? a - mod : a; }
// template <typename T1, typename ...Args> T1 add(T1 a, Args ... b) { return add(a, add(b...)); }
// struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } FastMod(int _m) {
// init(_m); } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } }
// Mod(mod); int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a,
// Args ...b) { return mul(a, mul(b...)); } int mul(int a, int b) { return 1ll * a * b % mod; } template
// <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); } template <typename T1, typename
// T2> T1 qp(T1 a, T2 b) { T1 ret = 1; for (; b; a = mul(a, a), b >>= 1) if (b & 1) ret = mul(ret, a); return
// ret; }

#define id(i, j) (((i)-1) * n + (j))
int n, q, t1, t2, a[N][N];
char ch[N];
int dx[] = { 1, 0 }, dy[] = { 0, 1 };

int pref[N][N];
#define query(x1, y1, x2, y2) (pref[x2][y2] - pref[x1 - 1][y2] - pref[x2][y1 - 1] + pref[x1 - 1][y1 - 1])

struct edge {
    int u, v, w;
    edge(int u, int v, int w) : u(u), v(v), w(w) {}
    bool operator<(const edge& b) const { return w > b.w; }
};
vector<edge> b;

vector<int> e[N * N << 1];
int fa[N * N], siz[N * N], act[N * N], tot, val[N * N << 1];
int find(int u) { return u == fa[u] ? u : fa[u] = find(fa[u]); }

int dep[N * N << 1], sizt[N * N << 1], fat[N * N << 1], son[N * N << 1], top[N * N << 1];
void find_hc(int u, int fk) {
    dep[u] = dep[fk] + 1, sizt[u] = 1;
    fat[u] = fk;
    for (auto v : e[u])
        if (v != fk) {
            find_hc(v, u);
            sizt[u] += sizt[v];
            if (sizt[v] > sizt[son[u]])
                son[u] = v;
        }
}
void con_hc(int u, int tp) {
    top[u] = tp;
    if (son[u])
        con_hc(son[u], tp);
    for (auto v : e[u])
        if (v != fat[u] && v != son[u])
            con_hc(v, v);
}
int LCA(int x, int y) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        x = fat[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n;
    rep(i, 1, n) {
        cin >> ch + 1;
        rep(j, 1, n) if (ch[j] == '#') pref[i][j] = 1;
    }
    rep(i, 1, n) rep(j, 1, n) pref[i][j] += pref[i - 1][j] + pref[i][j - 1] - pref[i - 1][j - 1];
    rep(i, 1, n) rep(j, 1, n) {
        int l = 0, r = min({ i, j, n - i + 1, n - j + 1 }), mid;
        while (l <= r) {
            mid = l + r >> 1;
            if (query(i - mid + 1, j - mid + 1, i + mid - 1, j + mid - 1) == 0)
                a[i][j] = mid, l = mid + 1;
            else
                r = mid - 1;
        }
    }

    rep(i, 1, n) rep(j, 1, n) if (query(i, j, i, j) == 0) {
        rep(k, 0, 1) if (i + dx[k] <= n and j + dy[k] <= n and i + dx[k] > 0 and j + dy[k] > 0)
            b.emplace_back(id(i, j), id(i + dx[k], j + dy[k]),
                           max(0, min(a[i][j] * 2 - 1, a[i + dx[k]][j + dy[k]] * 2 - 1)));
    }
    sort(b.begin(), b.end());

    tot = id(n, n);
    rep(i, 1, id(n, n)) fa[i] = i, act[i] = i, siz[i] = 1;
    for (edge x : b)
        if ((t1 = find(x.u)) != (t2 = find(x.v))) {
            ++tot;
            val[tot] = x.w;
            e[tot].emplace_back(act[t1]), e[tot].emplace_back(act[t2]);
            if (siz[t1] > siz[t2])
                swap(t1, t2);
            fa[t1] = t2;
            siz[t2] += siz[t1];
            act[t2] = tot;
        }
    cerr << tot << ' ' << (id(n, n) * 2) - 1 << endl;

    ++tot;

    rep(i, 1, id(n, n)) if (act[find(i)]) e[tot].emplace_back(act[find(i)]), act[find(i)] = 0;
    find_hc(tot, 0), con_hc(tot, 0);

    cin >> q;
    for (int x1, x2, y1, y2; q--;) {
        cin >> x1 >> y1 >> x2 >> y2;
        if (x1 == x2 and y1 == y2) {
            cout << max(0, a[x1][y1] * 2 - 1) << '\n';
        } else {
            x1 = val[LCA(id(x1, y1), id(x2, y2))];
            if (x1 == -1)
                x1 = 0;
            cout << x1 << '\n';
        }
    }
}


AGC001F

给出一个元素集合为\(\{1,2,\dots,N\}\) \((1\leq N\leq 500,000)\)的排列\(P\),当有\(i,j\) \((1\leq i<j\leq N)\)满足\(j-i\geq K\) \((1\leq K\leq N-1)\)\(|P_{i}-P_{j}|==1\)时,可以交换\(P_{i}\)\(P_{j}\)

求:可能排列中字典序最小的排列

一眼看过去发现这个限制不是很好满足。因为一眼看过去看错题了看成转化后的题意了
于是考虑构造排列 \(q\) 满足 \(q_{p_i} = i\)
然后发现相邻两个位置差值 \(\ge k\) 时可以交换。
依题意冒泡排序可以过 \(n = 5000\) 的数据。

然后 \(n=500000\) 考虑换一种做法,用 \(O(n\log n)\) 的归并排序。
归并考虑在 \(\text{mid}\) 后面的一个元素可以到当前归并指针位置当且仅当 \(\text{mid}\) 前面所有留下来的值都大于等于这个元素 \(+k\)。维护后缀最小值即可判断。

然后同样的转化成原排列即可。总时间复杂度 \(O(n\log n)\)

线段树优化建图?那是什么东西?

code
#include <bits/stdc++.h>
using namespace std; using ll = long long; using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
template<typename T> void get(T & x) {
	x = 0; char ch = getchar(); bool f = false; while (ch < '0' or ch > '9') f = f or ch == '-', ch = getchar();
	while ('0' <= ch and ch <= '9') x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); f && (x = -x); 
} template <typename T, typename ... Args> void get(T & a, Args & ... b) { get(a); get(b...); }
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
const int N = 5e5 + 10;
// const int B = 300;

// const int mod = 469762049, g = 3;
// const int mod = 998244353, g = 3;
// const int mod = 1004535809, g = 3;
// const int mod = 1e9 + 7;
// const int mod = 1e9 + 9;
// const int mod = 1e9 + 3579, bse = 131;
// const int inv2 = (mod + 1) >> 1;
// template <typename T1, typename T2> T1 add(T1 a, T2 b) { return (a += b) >= mod ? a - mod : a; }
// template <typename T1, typename ...Args> T1 add(T1 a, Args ... b) { return add(a, add(b...)); }
// struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } FastMod(int _m) { init(_m); } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod(mod);
// int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }
// int mul(int a, int b) { return 1ll * a * b % mod; } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }
// template <typename T1, typename T2> T1 qp(T1 a, T2 b) { T1 ret = 1; for (; b; a = mul(a, a), b >>= 1) if (b & 1) ret = mul(ret, a); return ret; }

int n, k, p[N], q[N];

int mn[N], tmp[N];
void sort(int l, int r) {
    if (l >= r) return;
    int mid = l + r >> 1;
    sort(l, mid); sort(mid+1, r);
    mn[mid + 1] = N; int ptr1 = l, ptr2 = mid + 1, ptr3 = l;
    pre(i,mid,l) mn[i] = min(mn[i + 1], q[i]);
    while (ptr1 <= mid and ptr2 <= r) {
        if (mn[ptr1] - k < q[ptr2]) tmp[ptr3 ++] = q[ptr1 ++];
        else tmp[ptr3 ++] = q[ptr2 ++];
    } 
    while (ptr1 <= mid) tmp[ptr3 ++] = q[ptr1 ++];
    while (ptr2 <= r) tmp[ptr3 ++] = q[ptr2 ++];
    rep(i,l,r) q[i] = tmp[i];
}

int main() {
    get(n, k); 
    rep(i,1,n) get(p[i]), q[p[i]] = i;
    sort(1, n);
    rep(i,1,n) p[q[i]] = i;
    rep(i,1,n) cout << p[i] << '\n';
}
posted @ 2022-11-11 19:57  joke3579  阅读(97)  评论(6编辑  收藏  举报