未来的瞳孔!
近在咫尺的视野盲点?!
2023/10/9 上午模拟赛,笔者被锤烂了。
但是,为什么想不到呢?
我通常将“直觉”作为导向,如果直觉是正确的,那么大概就有了。不过我做过的题少得可怜,因此直觉真的很不靠谱。什么都想不到,即使想到了也漏洞百出。
也许只有大量的训练才能根治这一问题,但也许我也看不见什么。
我们周围的环境中有着大量的微观粒子,它们都在阻挡我们的实现。也就是说,我们和瞎子无异。
造成这种情况实属可悲,但也无法避免。这是宇宙中最坏的结果,只能说可怜。
我们是低等文明吗?显然是。我们连地球上的东西都看不全。
也许那从来就不是盲点,这个世界的规则不许我们看到它们。亡灵游荡于世间,所认知的规则已经不再成立。
既然这样,视觉还有什么用呢?
欢迎收看十月大型新番《暂时没有名字》,上集回顾,大家非常想看续集,那么我们日更!
空间大盗与时间旅人

空间大盗是可以转移硬盘的存储顺序,从而让数据毁坏的。
我要向 @AC_love 宣战!学习自己喜欢的知识是一个人的自由,没有任何人可以阻止!
我要向 ACL 投出加农炮!捍卫老年高二选手的强大学习能力与做题能力,我辈义不容辞!!即使我是高二最弱战斗力,我也要站出来,不依赖时间旅人朋友的力量,大战邪恶势力!!
可以将这段话视作玩笑,没有任何引战的意思。大家好好学习,一起进步 !
!
Deltix Summer 2021 (Div. 1 + Div. 2)
你猜猜为什么随机到了这场呢?

Easy Problems
如果赶时间可以跳过。
A. A Variety of Operations
发现答案是 ,直接搞。
#include <bits/stdc++.h>
using namespace std;
int main(void) {
    int T; scanf("%d", &T); 
    while (T--) {
        int c, d; scanf("%d%d", &c, &d); 
        if (d > c) swap(c, d);
        if ((c - d) % 2 != 0) puts("-1");
        else {
            if (c == 0 && d == 0) puts("0");
            else if (c == d) puts("1");
            else puts("2");
        }
    }   
    return 0;
}B. Take Your Places!
对奇偶讨论一下就行。
#include <bits/stdc++.h>
using namespace std;
int n, even, odd;
int a[100005];
inline void calc1(void) {
    if (even != odd) return puts("-1"), void(); 
    int suma = 0, sumb = 0;
    int posa = 1, posb = 2;
    for (int i = 1; i <= n; ++i) if (a[i] % 2 == 0) {
        suma += abs(posa - i); posa += 2;
        sumb += abs(posb - i); posb += 2;
    }
    printf("%d\n", min(suma, sumb));
}
inline void calc2(void) {
    if (abs(even - odd) != 1) return puts("-1"), void(); 
    if (even > odd) {
        int pos = 1, ans = 0;
        for (int i = 1; i <= n; ++i)
            if (a[i] % 2 == 0) ans += abs(pos - i), pos += 2;
        printf("%d\n", ans);
    } else {
        int pos = 1, ans = 0;
        for (int i = 1; i <= n; ++i)
            if (a[i] % 2 == 1) ans += abs(pos - i), pos += 2;
        printf("%d\n", ans);
    }
}
int main(void) {
    int T; scanf("%d", &T); 
    while (T--) {
        scanf("%d", &n); even = 0, odd = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", a + i); 
            if (a[i] % 2 == 0) ++even;
            else ++odd;
        }
        if (n % 2 == 0) calc1();
        else calc2();
    }   
    return 0;
}C. Compressed Bracket Sequence
枚举即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long i64; 
i64 ans;
int n, c[1005];
int main(void) {
    scanf("%d", &n); 
    for (int i = 0; i < n; ++i) scanf("%d", c + i); 
    for (int l = 0; l < n; l += 2) {
        i64 cur = c[l], mn = c[l];
        for (int r = l + 1; r < n; ++r)
            if (r % 2 == 0) cur += c[r];
            else {
                i64 i = max(0ll, cur - c[r]);
                i64 j = min({mn, cur - 1, c[l] - 1ll});
                if (i <= j) ans += j - i + 1;
                cur -= c[r];
                mn = min(mn, cur);
            }
    }
    return !printf("%d\n", ans); 
}D. Take a Guess
按位或加按位与等于运算加,解方程就行。
#include <bits/stdc++.h>
using namespace std; 
int n, k, a[10005]; 
int qsum(int x, int y) {
    int s, t;
    cout << "and " << x << " " << y << endl; cin >> s; 
    cout << "or " << x << " " << y << endl; cin >> t; 
    return s + t; 
}
int main(void) {
    ios::sync_with_stdio(0); 
    cin >> n >> k; 
    int x = qsum(1, 2), y = qsum(1, 3), z = qsum(2, 3); 
    a[2] = (x - y + z) / 2; a[1] = x - a[2]; a[3] = z - a[2]; 
    for (int i = 4; i <= n; ++i) a[i] = qsum(1, i) - a[1]; 
    nth_element(a + 1, a + k, a + n + 1); 
    cout << "finish " << a[k] << endl; 
    return 0; 
}Medium Problems
有一定难度的问题。
E. Equilibrium
套路地,令 ,每次可以将奇数位置 ,偶数位置 ,问最少操作次数使之变成 。
将 前缀和一下,发现每次操作实际上是在前缀和区间上进行 组区间加。那么答案就直接推出来了:。当然需要判掉无解,也不难。
#include <bits/stdc++.h>
using namespace std; 
typedef long long i64; 
int n, q; 
int a[100005]; 
i64 s[100005]; 
i64 mn[17][100005], mx[17][100005]; 
inline i64 qmin(int l, int r) {
    int k = __lg(r - l + 1); 
    return min(mn[k][l], mn[k][r - (1 << k) + 1]); 
}
inline i64 qmax(int l, int r) {
    int k = __lg(r - l + 1); 
    return max(mx[k][l], mx[k][r - (1 << k) + 1]); 
}
int main(void) {
    ios::sync_with_stdio(0); 
    cin >> n >> q; 
    for (int i = 1; i <= n; ++i) cin >> a[i]; 
    for (int i = 1, x; i <= n; ++i) cin >> x, a[i] -= x; 
    for (int i = 1; i <= n; ++i) mn[0][i] = mx[0][i] = s[i] = s[i - 1] + a[i]; 
    for (int i = 1; i <= 17; ++i) for (int j = 1; j + (1 << i) - 1 <= n; ++j)
        mn[i][j] = min(mn[i - 1][j], mn[i - 1][j + (1 << i - 1)]), 
        mx[i][j] = max(mx[i - 1][j], mx[i - 1][j + (1 << i - 1)]); 
    while (q--) {
        int l, r; cin >> l >> r; 
        if (s[r] == s[l - 1] && qmax(l, r) <= s[l - 1]) cout << s[l - 1] - qmin(l, r) << "\n"; 
        else cout << "-1\n"; 
    }
    return 0; 
}* F. Sports Betting
有 个人,两两之间会打比赛。每人有一个实力值 ,在 与 的比赛中, 有 的概率获胜,其他情况则是 获胜。 在与 的比赛中获胜则称 打败了 。若 打败了 , 打败了 ,则认为 也打败了 。若 打败了除了他自己以外的所有人,则称 是一个 Winner(是否打败了自己不要求),注意 Winner 可能有多个。现在你需要求出 Winner 的期望数量,对 取模。
考虑状压 DP,设 代表 打败了 中人的概率。容斥,答案为:
预处理 ,那么:
时间复杂度 。
#include <bits/stdc++.h>
using namespace std; 
const int P = 1000000007; 
const int N = 2000000; 
int n; 
int a[1 << 14], f[14][1 << 14], g[14][1 << 14]; 
int inv[N + 5]; 
inline int lowbit(int x) { return x & -x; }
inline int calc(int T, int ST) {
    int res = 1; 
    for (int i = 0; i < n; ++i)
        if (T >> i & 1) res = 1ll * res * g[i][ST] % P; 
    return res; 
}
int main(void) {
    inv[1] = 1; 
    for (int i = 2; i <= N; ++i) inv[i] = 1ll * (P - P / i) * inv[P % i] % P; 
    scanf("%d", &n); 
    for (int i = 0; i < n; ++i) scanf("%d", &a[1 << i]); 
    for (int i = 0; i < n; ++i) {
        g[i][0] = 1; 
        for (int s = 1; s < 1 << n; ++s)
            g[i][s] = 1ll * g[i][s ^ lowbit(s)] * a[lowbit(s)] % P * inv[a[lowbit(s)] + a[1 << i]] % P; 
    }
    for (int i = 0; i < n; ++i)
        for (int s = 0; s < 1 << n; ++s) if (s >> i & 1) {
            f[i][s] = 1; 
            for (int t = (s - 1) & s; t; t = (t - 1) & s)
                f[i][s] = (f[i][s] - 1ll * f[i][t] * calc(t, s - t) % P) % P; 
        }
    int ans = 0; 
    for (int i = 0; i < n; ++i) ans = (ans + f[i][(1 << n) - 1]) % P; 
    printf("%d\n", (ans + P) % P); 
    return 0; 
}Hard Problems
比较困难的问题。
** G. Gates to Another World
- 有 个点,编号为 的点之间有无向边当且仅当 。
- 有 次操作,每次询问 是否能互相到达,或者删除编号在 之间的所有点,保证没有点会被删除两次。
- 。
考虑逆时旅人,将删点改成加点。
最主要的问题是,如何用一种方式来压缩图?对于一个没有被删点的连续 段,一定是连通的。这种方式与线段树有直接关系,考虑用线段树结构来刻画这个东西,然后点数就与删点次数有关。
注意一个位置只会被删除一次,这很好,我们可以在线段树上区间染色,代表这些点存活到了 时刻。
这样对于动态开点线段树上的存在的点,才是有意义的点,其余所有点都可以被映射到它们身上。对于每个节点将在 时刻将它的左右儿子分裂开(不再连通),逆时旅人并查集维护即可。
本题卡空间,注意你的内存消耗 。
。
#include <bits/stdc++.h>
using namespace std; 
typedef long long i64; 
const int N = 50005 * 120; 
struct Query {
    string op; 
    i64 x, y; 
} Q[50005]; 
int n, m, ans[50005]; 
int fa[N + 5]; 
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int ls[N + 5], rs[N + 5], dat[N + 5], tot; 
#define leaf(o) (!ls[o] && !rs[o])
inline void pushdown(int o) {
    if (!ls[o]) ls[o] = ++tot; if (!rs[o]) rs[o] = ++tot; 
    if (dat[o]) dat[ls[o]] = dat[rs[o]] = dat[o], dat[o] = 0; 
}
void update(int o, i64 l, i64 r, i64 x, i64 y, int t) {
    if (x <= l && r <= y) return dat[o] = t, void(); 
    pushdown(o); i64 mid = l + r >> 1; 
    if (x <= mid) update(ls[o], l, mid, x, y, t); 
    if (mid < y) update(rs[o], mid + 1, r, x, y, t); 
}
int locate(int o, i64 l, i64 r, i64 p) {
    if (leaf(o)) return o; i64 mid = l + r >> 1; 
    if (p <= mid) return locate(ls[o], l, mid, p); 
    return locate(rs[o], mid + 1, r, p); 
}
vector<pair<int, int>> edge[50005]; 
void connect(int x, int y) {
    if (leaf(x) && leaf(y)) return edge[min(dat[x], dat[y])].emplace_back(x, y), void(); 
    if (leaf(x)) return connect(x, ls[y]), connect(x, rs[y]); 
    if (leaf(y)) return connect(ls[x], y), connect(rs[x], y); 
    connect(ls[x], ls[y]); connect(rs[x], rs[y]); 
}
int main(void) {
    for (int i = 1; i <= N; ++i) fa[i] = i; 
    ios_base::sync_with_stdio(0); 
    
    cin >> n >> m; i64 u = 1ll << n; 
    dat[++tot] = m + 1; 
    for (int i = 1; i <= m; ++i) {
        cin >> Q[i].op >> Q[i].x >> Q[i].y; 
        if (Q[i].op == "block") update(1, 0, u - 1, Q[i].x, Q[i].y, i); 
    }
    for (int i = 1; i <= tot; ++i) if (!leaf(i)) connect(ls[i], rs[i]); 
    for (int i = m + 1; i >= 1; --i) {
        for (auto [u, v] : edge[i]) fa[find(u)] = find(v); 
        if (Q[i].op == "ask") ans[i] = (find(locate(1, 0, u - 1, Q[i].x)) == find(locate(1, 0, u - 1, Q[i].y))); 
    }
    for (int i = 1; i <= m; ++i) if (Q[i].op == "ask") cout << ans[i] << 
    "\n"; 
    return 0; 
}** H. DIY Tree
给定一个 个点的无向带权完全图,找出一个满足第 个度数 的最小生成树。。
本题正解需要使用拟阵,但是此内容在算法竞赛中的应用不多,对笔者来说学习的收益过低,因此这里写一下本题的随机化做法。
sto lsy orz!
给生成树定义估价函数 ,其中 代表实际度数。
先求出最小生成树,然后对其进行调整。每次选择一条边权最大的,删去后 会减小的边 ,替换成加上后 不会变大的边权最小的边 ,时间复杂度为 。
随机化这个过程,我们给 和 的选择加上一个概率,不选就接着扫。
#include <bits/stdc++.h>
using namespace std; 
mt19937 Rand(time(0));
int n, k; 
int a[55], G[55][55];  
struct edge {
    int u, v, w, f; 
    edge(int u = 0, int v = 0, int w = 0) : u(u), v(v), w(w) {}
    bool operator< (const edge &a) const { return w < a.w; }
}; 
vector<edge> e; 
int Ans = 1e9; 
int fa[55];  
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int d[55]; 
inline int f(void) {
    int r = 0; 
    for (int i = 1; i <= k; ++i) r += max(0, d[i] - a[i]); 
    return r; 
}
void solve(void) {
    // cerr << "SOLVE\n"; 
    int ans = 0; 
    for (int i = 1; i <= n; ++i) fa[i] = i, d[i] = 0; 
    for (auto &it : e) {
        it.f = 0; 
        int u = find(it.u), v = find(it.v); 
        if (u == v) continue; fa[u] = v; 
        ans += it.w; ++d[it.u]; ++d[it.v]; it.f = 1; 
    }
    int now = 0; 
    while (now = f()) {
        // cerr << now << "\n"; 
        int p = -1; 
        while (p == -1) {
            for (int i = e.size() - 1; i >= 0; --i) {
                auto &it = e[i]; 
                if (it.f && (d[it.u] > a[it.u] || d[it.v] > a[it.v]) && Rand() % 4) { 
                    --d[it.u], --d[it.v]; ans -= it.w; it.f = 0; 
                    p = i; break; 
                }
            }
        }
        for (int i = 1; i <= n; ++i) fa[i] = i; 
        for (auto &it : e) if (it.f) fa[find(it.u)] = find(it.v); 
        int tmp = 1e9; 
        for (int i = 0; i < e.size(); ++i) {
            auto &it = e[i]; 
            if (i != p && !it.f && find(it.u) != find(it.v)) {
                ++d[it.u]; ++d[it.v]; 
                tmp = min(tmp, f() - now); 
                --d[it.u]; --d[it.v]; 
            }
        }
        bool flag = 0; 
        while (!flag) {
            for (int i = 0; i < e.size(); ++i) {
                auto &it = e[i]; 
                if (i != p && !it.f && find(it.u) != find(it.v)) {
                    ++d[it.u]; ++d[it.v]; 
                    if ((f() - now < 0 || tmp >= 0) && Rand() % 4) { it.f = 1, ans += it.w, flag = 1; break; } 
                    --d[it.u]; --d[it.v]; 
                }
            }
        }
    }
    Ans = min(Ans, ans); 
}
int main(void) {
    ios_base::sync_with_stdio(0); 
    cin >> n >> k; 
    for (int i = 1; i <= k; ++i) cin >> a[i]; 
    for (int i = k + 1; i <= n; ++i) a[i] = 1e9; 
    for (int i = 1, x; i < n; ++i) for (int j = i + 1; j <= n; ++j)
        cin >> x, e.emplace_back(i, j, x); 
    sort(e.begin(), e.end()); 
    double st = clock(); 
    do solve(); while (1000 * (clock() - st) / CLOCKS_PER_SEC < 5700); 
    cout << Ans << "\n"; 
    return 0; 
}After Memories
我们可以相信我们的视觉吗?
在当下的情况,也许我们可以小心翼翼地踱步,来保证不要看不清会导致我们摔倒的东西。
但这也只是表象,我们依然无法看清一切。当忽略的东西足够多,终将酿成大祸。
也许这就是生命终结的原因。如果有生物可以看清一切,那我相信它们是永生的。

 
          
          
          
        