2017微软探星夏令营在线技术笔试

好久没在csdn上写东西了。

1534 : Array Partition


求一个前缀和,然后用map维护一下就好了。



1535 : MSFT

这题还是有一点意思的。因为出现两次的字符只有4个。于是考虑2^8枚举两个字符串中替换字符串中重复字符的位置。比如mma可以被替换成 Mma或者mMa。于是拿到的就是两个不含重复字符的串。然后求最少交换次数。试想:其实每次交换就是一次位置变换。然后考虑将变换拆成轮换的形式。那么每一个轮换需要的交换次数就是size-1.于是暴力搞一下就好了。

#include <bits/stdc++.h>

using namespace std;

char ch1[44], ch2[44];
int sit1[44], sit2[44];

int gao(int n) {
    map<int, int> mp;
    for (int i = 0; i < n; i ++) {
        mp[sit1[i]] = i;
    }
    int b[44];
    for (int i = 0; i < n; i ++) {
        b[i] = mp[sit2[i]];
    }
    bool vis[44] = {0};
    int res = 0;
    for (int i = 0; i < n; i ++) {
        if (vis[i]) continue;
        int now = i, cnt = 0;
        while (!vis[now]) {
            cnt ++;
            vis[now] = true;
            now = b[now];
        }
        res += cnt - 1;
    }
    return res;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T --) {
        scanf("%s%s", ch1, ch2);
        int n = strlen(ch1);
        int cnt[33] = {0};
        for (int i = 0; i < n; ++i) {
            cnt[ch1[i] - 'a'] ++;
            sit1[i] = ch1[i] - 'a';
        }
        for (int i = 0; i < n; ++i) {
            sit2[i] = ch2[i] - 'a';
        }
        int num = 0;
        vector<char> vec;
        if (cnt['m' - 'a'] == 2) vec.push_back('m'), num ++;
        if (cnt['s' - 'a'] == 2) vec.push_back('s'), num ++;
        if (cnt['f' - 'a'] == 2) vec.push_back('f'), num ++;
        if (cnt['t' - 'a'] == 2) vec.push_back('t'), num ++;
        int ans = n;
        if (num == 0) ans = min(ans, gao(n));
        for (int i = 0; i < (1<<(num+num)); i ++) {
            for (int j = 0; j < num; j ++) {
                int tmp = 0;
                int cc1 = (i>>j) & 1;
                int cc2 = (i>>(j+num)) & 1;
                for (int k = 0; k < n; k ++) {
                    if (ch1[k] == vec[j]) {
                        if (cc1 == 0) sit1[k] += 26;
                        cc1 --;
                    }
                    if (ch2[k] == vec[j]) {
                        if (cc2 == 0) sit2[k] += 26;
                        cc2 --;
                    }
                }
            }
            ans = min(ans, gao(n));
            for (int j = 0; j < num; j ++) {
                int tmp = 0;
                int cc1 = (i>>j) & 1;
                int cc2 = (i>>(j+num)) & 1;
                for (int k = 0; k < n; k ++) {
                    if (ch1[k] == vec[j]) {
                        if (cc1 == 0) sit1[k] -= 26;
                        cc1 --;
                    }
                    if (ch2[k] == vec[j]) {
                        if (cc2 == 0) sit2[k] -= 26;
                        cc2 --;
                    }
                }
            }
        }
        printf("%d\n", ans);
        
    }
    return 0;
}


1536 : Selling Antique Coins


这个题目还是蛮有意思的。首先,可以知道的是。如果我们每次考虑放一个比当前安排好的序列都大的硬币。那么显然当前这个的情况是易见的。那么最大的硬币有两种放的方式:

1.直接放到前一个最大的旁边。于是作用就是次大的失效,最大的生效。

2.考虑最大的和次大的“同时”生效。于是,可以设置dp状态为dp[i][j]。表示放第i大数时,有j个有效数字,有效数字是指被统计在答案中,并且无效数字均在最大数字(第i个数)的右边,且未被统计。于是新+的数Ai可以考虑为与Ai-1间隔了r个数字。于是有了代码中的转移。

#include <algorithm>
#include <stdio.h>
#include <cstring>
#include <vector>

using namespace std;

int a[5555];
pair<int, int> p[5555];

int dp[5555][5555];

int main() {
    int n, r, T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &r);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        for (int i = 1; i <= n; i++) {
            int b; scanf("%d", &b);
            p[i] = make_pair<>(a[i], b);
        }
        sort(p + 1, p + n + 1);
        memset(dp, 0, sizeof(dp));
        int ans = p[n].second;
        dp[1][1] = p[1].second;
        for (int i = 2; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i][j] = max(dp[i][j], dp[i - 1][j] + p[i].second - p[i - 1].second);
            }
            for (int j = 0; j <= i; j++) {
                int k = max(i - r - j - 1, 0);
                int s = min(i, k + r + 1);
                dp[i][s] = max(dp[i][s], dp[i - 1][k] + p[i].second);
            }
            for (int j = 1; j <= i; j++) {
                dp[i][j] = max(dp[i][j], dp[i][j - 1]);
            }
        }
        ans = max(ans, dp[n][n]);
        printf("%d\n", ans);
    }
    return 0;
}
/*
333
3 1
1 2 3
44 1 1

5 1
1 2 3 4 5
1 100 1 1 1
4 2
100 200 300 400
100 200 300 400
4 2
1 2 3 4
4 3 2 1
4 1
1 2 3 4
4 3 2 1
*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值