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';
}

浙公网安备 33010602011771号