腾讯笔试第5题

题意: 大概就是两种颜色的数,数字是1 - n的,总共2n个数,然后每次可以交换相邻两个数字,最后让两种颜色的数字都是从小到大排序的。
举个例子
RBBRBR 颜色
231123
最终要结果是
RRBBBR
121233
也就是把R1移到了最前的位置,B3移到了B2后面。这样总共交换了 5次,所以结果是 5。

题解: dp[i][j] 表示状态为前 i + j 已经放了i个红色,j个黑色,那么后面一个要么把 i + 1 的红色移到后面,要么是 把j + 1的黑色移到后面。所以只要知道这两种状态的移到后面来需要的步数就可以了。这个步数就是 原本的位置 - 在他前面已经排好了的数字个数,在他前面排好的数字个数又有两种颜色,不过没影响直接预处理就行了。
{ d p [ i + 1 ] [ j ] = m i n ( d p [ i + 1 ] [ j ] , d p [ i ] [ j ] + p o s − m i r [ p o s ] [ i + 1 ] − m i b [ p o s ] [ j ] ) ; d p [ i ] [ j + 1 ] = m i n ( d p [ i ] [ j + 1 ] , d p [ i ] [ j ] + p o s − m i b [ p o s ] [ j + 1 ] − m i r [ p o s ] [ i ] ) ; \begin{cases} dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + pos - mir[pos][i + 1] - mib[pos][j]);\\ dp[i][j + 1] = min(dp[i][j + 1], dp[i][j] + pos - mib[pos][j + 1] - mir[pos][i]); \end{cases} {dp[i+1][j]=min(dp[i+1][j],dp[i][j]+posmir[pos][i+1]mib[pos][j]);dp[i][j+1]=min(dp[i][j+1],dp[i][j]+posmib[pos][j+1]mir[pos][i]);

mir[pos][i] pos位置 左边小于 i 的红色棋子个数
mir[pos][j] pos位置 左边小于 j 的黑色棋子个数

#include "bits/stdc++.h"

using namespace std;

int n;

int mir[6005][3005], mib[6005][3005];
int dp[3005][3005];

unordered_map<int, int> mpr, mpb;

int main() {
    while (cin >> n) {
        string s;
        cin >> s;
        vector<int> v;
        for (int i = 0; i < 2 * n; i++) {
            int x;
            cin >> x;
            if (s[i] == 'R') {
                mpr[x] = i; //红色数字的位置
            } else {
                mpb[x] = i; //黑色数字的位置
            }
            v.emplace_back(x);
        }
        memset(mir, 0, sizeof(mir));
        for (int i = 0; i < 2 * n; i++) { //预处理
            if (i == 0)continue;
            if (s[i - 1] == 'R') {
                for (int j = 1; j <= n; j++) {
                    mib[i][j] = mib[i - 1][j];
                }
                for (int j = 1; j <= n; j++) {
                    if (j >= v[i - 1]) {
                        mir[i][j] = mir[i - 1][j] + 1;
                    } else {
                        mir[i][j] = mir[i - 1][j];
                    }
                }
            } else {
                for (int j = 1; j <= n; j++) {
                    mir[i][j] = mir[i - 1][j];
                }
                for (int j = 1; j <= n; j++) {
                    if (j >= v[i - 1]) {
                        mib[i][j] = mib[i - 1][j] + 1;
                    } else {
                        mib[i][j] = mib[i - 1][j];
                    }
                }
            }

        }
        memset(dp, 1, sizeof(dp));
        dp[0][0] = 0;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                int pos = mpr[i + 1];
                if (i + 1 <= n) {
                    dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + pos - mir[pos][i + 1] - mib[pos][j]);
                }
                if (j + 1 <= n) {
                    pos = mpb[j + 1];
                    dp[i][j + 1] = min(dp[i][j + 1], dp[i][j] + pos - mib[pos][j + 1] - mir[pos][i]);
                }
            }
        }
        printf("%d\n", dp[n][n]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值