B. Swaps

https://codeforces.com/problemset/problem/1573/B

题意:给定一个长度为n的奇数数组a和偶数数组b,数值的范围是1~2n。现在可以对任意相邻的字符进行交换,问最少经过多少次交换,可以使得数组a在逻辑上小于数组b。

思路:a和b中没有相同字符,所以让数组a逻辑上小于数组b,只要保证第一个数字满足要求即可。于是,对数组b维护一个st表,对于a中的每个位置i,考虑比a[i]大的所有数组b中的元素,移动到b的第一个位置所需要的最小代价和i移动到第一个位置的代价和,取最小的一个即可。

总结:思路是有的,st表太久没写细节忘记了,还好整理了模板,直接套就行
https://github.com/yxc-s/programming-template/blob/master/Algorithms/Dst.h
st的思路是:1、先求出能代表长度n的一个2的幂次数值。2、初始化dp[i][0] = a[0]。3、状态转移 dp[i][k] = merge(dp[i][k - 1], dp[i + (1 << (k - 1))][k - 1])。 4、求解问题,得到我们需要的区间[l, r],然后求出一个区间长度len,求出幂次表示,即可得到merge(dp[l][p], dp[r - (1 << p) + 1][p])

inline void solve() {
    int n;
    cin >> n;

    vector<int> a(n), b(n + 1);
    for (auto& x : a) {
        cin >> x;
    }

    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        b[x / 2] = i;
    }

    int p;
    for (p = 1; (1 << p) <= n; ++p);
    p --;

    vector<vector<int>> dp (n + 1, vector<int> (p + 1));
    for (int i = 1; i <= n; ++i){
        dp[i][0] = b[i];
    }

    auto merge = [](const auto& lseg, const auto& rseg) {
        return min(lseg, rseg);
    };

    for (int k = 1; k <= p; ++k){
        for (int i = 1; i + (1 << k) - 1 <= n; ++i){
            dp[i][k] = merge(dp[i][k - 1], dp[i + (1 << (k - 1))][k - 1]);
        }
    }

    int ans = n * 2;
    for (int i = 0; i < n; ++i) {
        int v = a[i];
        int l = (v + 1) / 2;
        int r = n;
        int len = r - l + 1;
        for (p = 1; (1 << p) <= len; ++p);
        p --;
        auto res = merge(dp[l][p], dp[r - (1 << p) + 1][p]);
        ans = min(ans, res - 1 + i);
    }

    cout << ans << '\n';
}
posted @ 2026-01-08 10:28  _Yxc  阅读(3)  评论(0)    收藏  举报