20241104

T1

火星人的 DNA

显然单调,直接双指针。过程中维护每个限制还需要多少对应字符才能达成,拿个 set 每次取最大值和 \(0\) 比较即可判断当前是否合法。

代码
#include <iostream>
#include <set>
using namespace std;
multiset<int> st;
int n, k, q, ans = 2147483647;
int a[200005];
int req[200005];
void Add(int x, int y) {
    x = a[x];
    st.erase(st.find(req[x]));
    req[x] += y;
    st.insert(req[x]);
}
int main() {
    freopen("dna.in", "r", stdin);
    freopen("dna.out", "w", stdout);
    cin >> n >> k >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1, x, y; i <= q; i++) {
        cin >> x >> y;
        req[x] = y;
    }
    for (int i = 0; i < k; i++) st.insert(req[i]);
    for (int i = 1, j = 0; i <= n; i++) {
        while (j < n && *st.rbegin() > 0) Add(++j, -1);
        if (*st.rbegin() <= 0) {
            ans = min(ans, j - i + 1);
            // cout << i << " " << j << "\n";
        }
        Add(i, 1);
    }
    if (ans == 2147483647) 
        cout << "impossible\n";
    else 
        cout << ans << "\n";
    return 0;
}

T2

石头

发现最大值是特殊的,在最大值左边的东西会先把左边扩展完,然后挨个扩展右边。右边的同理。于是可以考虑启发式分治,每次根据最大值递归,并考虑两边互相以及当前分治中心的贡献。两边互相的贡献是容易统计的,右边的所有起始位置会向位置在左边的、满足特定条件的所有询问产生贡献。特定条件指的是 \(p + k = C\)\(p - k = C\)。左边向右边同理。然后考虑当前分治中心对区间内所有询问的贡献。我们考虑枚举左右之中短的一边,则每次形如先走一个数,然后扩展另外一边的一段,然后再走一个数,以此类推。每次走一个位置时对当前位置上的询问产生的贡献是容易计算的,随便拿个什么东西记录即可。而对于另外一边,其实也是对于位置在一段区间内的、满足 \(p + k = C\)\(p - k = C\) 的所有询问产生贡献。所有贡献离线下来按横坐标升序枚举,过程中数组维护每个位置的值即可。注意加和减的限制要分开统计。

代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cassert>
#include <map>
// #define int long long
using namespace std;
int n, q;
int a[100005];
pair<int, int> mx[17][100005];
int lg2[100005];
int Qmax(int l, int r, int t) {
    assert(r >= l);
    int k = lg2[r - l + 1];
    pair<int, int> tmp = max(mx[k][l], mx[k][r - (1 << k) + 1]);
    return t ? tmp.second : tmp.first;
}
int p[100005], k[100005];
struct qquery {
    int x, y, v, id;
} qs1[500005], qs2[500005];
int ASDF[400005];
int ans[100005];
int *val = &ASDF[200002];
int qcnt1, qcnt2;
map<int, int> mp[100005];
void Solve(int l, int r) {
    if (l > r) 
        return;
    // cerr << l << " " << r << "\n";
    int x = Qmax(l, r, 1);
    if (x != r) {
        int a = r - x;
        qs1[++qcnt1] = (qquery) { l, a + x + 1, a, 0 };
        qs1[++qcnt1] = (qquery) { x + 1, a + x + 1, -a, 0 };
    }
    if (x != l) {
        int a = x - l;
        qs2[++qcnt2] = (qquery) { x, a - x + 1, a, 0 };
        qs2[++qcnt2] = (qquery) { r + 1, a - x + 1, -a, 0 };
    }
    if (r - x <= x - l) {
        for (int i = x, cur = 1, cl = x; i <= r; i++) {
            ++mp[i][cur];
            int ll = l, rr = cl - 1, mid, ans = cl;
            while (ll <= rr) {
                mid = (ll + rr) >> 1;
                if (Qmax(mid, cl - 1, 0) < a[i + 1]) 
                    ans = mid, rr = mid - 1;
                else 
                    ll = mid + 1;
            }
            if (ans != cl) {
                qs1[++qcnt1] = (qquery) { ans, cur + cl, 1, 0 };
                qs1[++qcnt1] = (qquery) { cl, cur + cl, -1, 0 };
            }
            cur += (cl - ans), cl = ans;
            ++cur;
        }
    } else {
        for (int i = x, cur = 1, cr = x; i >= l; i--) {
            ++mp[i][cur];
            int ll = cr + 1, rr = r, mid, ans = cr;
            while (ll <= rr) {
                mid = (ll + rr) >> 1;
                if (Qmax(cr + 1, mid, 0) < a[i - 1]) 
                    ans = mid, ll = mid + 1;
                else 
                    rr = mid - 1;
            }
            if (ans != cr) {
                qs2[++qcnt2] = (qquery) { cr + 1, cur - cr, 1, 0 };
                qs2[++qcnt2] = (qquery) { ans + 1, cur - cr, -1, 0 };
            }
            cur += (ans - cr), cr = ans;
            ++cur;
        }
    }
    Solve(l, x - 1);
    Solve(x + 1, r);
}
signed main() {
    freopen("stone.in", "r", stdin);
    freopen("stone.out", "w", stdout);
    cin >> n >> q;
    a[0] = a[n + 1] = 2147483647;
    lg2[0] = -1;
    for (int i = 1; i <= n; i++) cin >> a[i], mx[0][i] = make_pair(a[i], i), lg2[i] = lg2[i - 1] + ((i & (i - 1)) == 0);
    for (int i = 1; (1 << i) <= n; i++) {
        for (int j = 1; j + (1 << i) - 1 <= n; j++) 
            mx[i][j] = max(mx[i - 1][j], mx[i - 1][j + (1 << (i - 1))]);
    }
    // cerr << qcnt1 << " " << qcnt2 << "\n";
    Solve(1, n);
    for (int i = 1; i <= q; i++) {
        cin >> p[i] >> k[i];
        qs1[++qcnt1] = (qquery) { p[i], k[i] + p[i], 0, i };
        qs2[++qcnt2] = (qquery) { p[i], k[i] - p[i], 0, i };
    }
    sort(qs1 + 1, qs1 + qcnt1 + 1, [](qquery a, qquery b) { return a.x == b.x ? (a.id < b.id) : (a.x < b.x); });
    for (int i = 1; i <= qcnt1; i++) {
        if (qs1[i].id) 
            ans[qs1[i].id] += val[qs1[i].y];
        else 
            val[qs1[i].y] += qs1[i].v;
    }

    memset(ASDF, 0, sizeof ASDF);
    sort(qs2 + 1, qs2 + qcnt2 + 1, [](qquery a, qquery b) { return a.x == b.x ? (a.id < b.id) : (a.x < b.x); });
    for (int i = 1; i <= qcnt2; i++) {
        if (qs2[i].id) 
            ans[qs2[i].id] += val[qs2[i].y];
        else 
            val[qs2[i].y] += qs2[i].v;
    }
    for (int i = 1; i <= q; i++) cout << ans[i] + mp[p[i]][k[i]] << "\n";
    return 0;
}

T3

字符串问题

将每个长度为 \(2\) 的子串视为边,则构成三个点的有向图,要求图中欧拉回路 / 路径的数量。直接套 BEST 定理即可。对于欧拉路径,只需要枚举起点终点,然后就一样做。

代码
#include <iostream>
#include <string.h>
#define int long long
using namespace std;
const int P = 1000000007;
int qpow(int x, int y) {
    int ret = 1;
    while (y) {
        if (y & 1) 
            ret = ret * x % P;
        y >>= 1;
        x = x * x % P;
    }
    return ret;
}
struct DSU {
    int f[10];
    void ini(int x) { for (; ~x; --x) f[x] = x; }
    int getf(int x) { return (f[x] == x ? x : (f[x] = getf(f[x]))); }
    void Merge(int x, int y) {
        x = getf(x), y = getf(y);
        (x != y) ? (f[x] = y) : 0;
    }
} dsu;
int A[10][10];
int g[10][10];
int out[10], in[10];
int n;
int det() {
    for (int i = 0; i < n; i++) A[i][i] = out[i];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) 
            A[i][j] = (A[i][j] + P - g[i][j]) % P;
    }
    if (n == 3) 
        return (A[0][0] * A[1][1] - A[0][1] * A[1][0] % P + P) % P;
    if (n == 2) 
        return A[0][0];
    return 1;
}
int a[20];
bool Isolated[10];
int fac[1000005];
int ifac[1000005];
int coef = 1;
signed main() {
    freopen("str.in", "r", stdin);
    freopen("str.out", "w", stdout);
    ifac[0] = fac[0] = 1;
    for (int i = 1; i <= 1000000; i++) fac[i] = fac[i - 1] * i % P, ifac[i] = qpow(fac[i], P - 2);
    int t;
    cin >> t;
    cin >> t;
    while (t--) {
        memset(Isolated, 0, sizeof Isolated);
        memset(out, 0, sizeof out);
        memset(in, 0, sizeof in);
        memset(g, 0, sizeof g);
        memset(A, 0, sizeof A);
        memset(a, 0, sizeof a);
        n = 0;
        coef = 1;
        string str;
        cin >> str;
        int asdf = str.size();
        if (asdf == 1) {
            cout << "3\n";
            continue;
        }
        for (int i = 0; i < asdf - 1; i++) ++a[(str[i] - 'a') * 3 + (str[i + 1] - 'a')];
        dsu.ini(3);
        for (int i = 0; i < 9; i++) {
            int x = i / 3, y = i % 3;
            g[x][y] += a[i];
            out[x] += a[i], in[y] += a[i];
            coef = coef * ifac[a[i]] % P;
            if (a[i]) 
                dsu.Merge(x, y);
        }
        int lst = -1;
        for (int i = 0; i < 3; i++) {
            int x = dsu.getf(i);
            if (!out[x] && !in[x]) {
                Isolated[i] = 1;
                continue;
            }
            lst = x;
            ++n;
        }
        for (int i = 0, t = 0; i < 3; i++) {
            if (Isolated[i]) 
                continue;
            for (int j = 0; j < 3; j++) g[t][j] = g[i][j];
            in[t] = in[i];
            out[t] = out[i];
            ++t;
        }
        for (int i = 0, t = 0; i < 3; i++) {
            if (Isolated[i]) 
                continue;
            for (int j = 0; j < 3; j++) g[j][t] = g[j][i];
            ++t;
        }
        int s = -1, t = -1, cnt = 0;
        for (int i = 0; i < n; i++) {
            (out[i] == in[i] + 1) ? (s = i) : 0;
            (in[i] == out[i] + 1) ? (t = i) : 0;
            (in[i] == out[i]) ? (++cnt) : 0;
        }
        if (s != -1 && t != -1) {
            ++in[s], ++out[t];
            g[t][s]++;
            cnt += 2;
        }
        if (s != -1) {
            int tmp = det() * coef % P;
            for (int i = 0; i < n; i++) tmp = tmp * fac[in[i] - 1] % P;
            cout << tmp << "\n";
        } else {
            int s = 0;
            for (int i = 0; i < n; i++) s += out[i];
            int tmp = det() * coef % P * s % P;
            for (int i = 0; i < n; i++) tmp = tmp * fac[in[i] - 1] % P;
            cout << tmp << "\n";
        }
    }
    return 0;
}

T4

基础图论练习题

不会。

posted @ 2024-11-04 22:35  forgotmyhandle  阅读(9)  评论(0)    收藏  举报