联想笔试811

联想笔试811

题目1

输入一个长度为n的仅包含英文字母的字符串,下标从1开始。你对这个字符串进行如下操作Q次,第i次操作如下:
l_i,r_i,k,表示复制原串中下标为l_i,l_i + 1,…,r_i;的字符串,之后:如果k=0,则将其粘贴在字符串的前面;如果k=1,则将其粘贴在字符串的末尾。
你需要输出经过Q次操作之后得到的字符串。

输入描述
第一行两个正整数n,Q(1小于等于n,Q小于等于2x10^4)。
第二行一个长度为n的仅包含英文字母的字符串。
第三行包含Q个正整数:l_1,l_2,…,l_Q;
第四行包含Q个正整数: r_1,r_2, …,r_Q;
第五行包含Q个正整数: k_1,k_2,…,k_Q。
数据保证: 1小于等于l_i小于等于r_i小于等于n,0 小于等于r_i-l_i <10,k_i属于 {0,1} ,且输入的区间范围合法。

输出描述
输出一行,表示最后得到的字符串。

样例输入
7 2
Xabcdez
2 1
4 7
0 1

样例输出
abcXabcdezXabcdez

#include <iostream>
#include <string>
#include <vector>

int main() {
    
    
    int n, q;
    std::cin >> n >> q;  // 输入字符串长度n和操作次数q
    
    std::string original_str;
    std::cin >> original_str;  // 输入原始字符串

    std::vector<int> l_values(q);
    std::vector<int> r_values(q);
    std::vector<int> k_values(q);

    for (int i = 0; i < q; ++i) {
    
    
        std::cin >> l_values[i];  // 输入每次操作的起始下标l
    }

    for (int i = 0; i < q; ++i) {
    
    
        std::cin >> r_values[i];  // 输入每次操作的结束下标r
    }

    for (int i = 0; i < q; ++i) {
    
    
        std::cin >> k_values[i];  // 输入每次操作的粘贴位置k
    }

    std::string result = original_str;  // 初始化结果字符串为原始字符串

    for (int i = 0; i < q; ++i) {
    
    
        int l = l_values[i];
        int r = r_values[i];
        int k = k_values[i];

        // 从原始字符串中复制指定范围的子串
        std::string copied_str = original_str.substr(l - 1, r - l + 1);

        if (k == 0) {
    
    
            // 如果粘贴位置k为0,则将复制的子串粘贴在结果字符串的前面
            result = copied_str + result;
        } else {
    
    
            // 如果粘贴位置k为1,则将复制的子串粘贴在结果字符串的末尾
            result = result + copied_str;
        }
    }

    std::cout << result << std::endl;  // 输出最终得到的字符串

    return 0;
}

题目2

定义f(A)表示将序列 A 进行 unique 操作之后的序列的元素个数。
unique 操作是指将相邻且相同的元素合成一个元素,再按照原序列的相对顺序进行排列之后得到的序列。
例如,
[1,1,1,2,2,3,3,1]进行unique 操作之后的序列为[1,2,3,1];[1,2,3,3,2,1]进行 unique 操作之后的序列为[1,2,3,2,1];[1,1,1,1,1]进行unique操作之后得到的序列为[1]。
现在,输入一个长度为n的序列S,你需要将其划分为k段,使得每一段都不为空,且你需要最大化所有段的f函数的值之和。你只需要输出这个最大值就行。

输入描述
第一行两个正整数n,k(1小于等于k小于等于n小于等于10的5次方);
第二行n个由空格隔开的正整数a_1,a_2…a_n(1小于等于a_i 小于等于10000),表示输入的序列S。

输出描述
输出一个整数,表示所求的最大值。

样例输入
8 3
1 1 1 2 2 3 3 1
样例输出
6
样例解释
按照如下划分:
[1], [1 1 2 2 3], [3 1]
第一段的函数值为 1,第二段的函数值为 3,第三段的函数值为 2,加起来为 6。可以证明没有比该方案还要更大的方案。

思路:
动态规划

使用两层循环,外层循环遍历所有元素,内层循环遍历所有可能的段数。在内层循环中,考虑将前p个元素划分为j-1段,并将剩余的元素作为第j段。为了找到最大的划分方案,我们使用一个变量maxVal来记录每个可能的划分的f值之和,并在内层循环结束后将最大值更新到dp[i][j]中。

最终,输出dp[n][k]即为所求的最大值,表示将整个序列划分为k段时的最大f值之和。

f函数用于计算经过unique操作后的序列的元素个数,它在代码中的作用是为了计算每个划分的f值,从而辅助动态规划的计算。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 定义函数 f,计算序列 segment 经过 unique 操作后的元素个数
int f(const vector<int>& segment) {
    
    
    vector<int> uniqueSegment;
    for (int i = 0; i < segment.size(); ++i) {
    
    
        if (i == 0 || segment[i] != segment[i - 1]) {
    
    
            uniqueSegment.push_back(segment[i]);
        }
    }
    return uniqueSegment.size();
}

int main() {
    
    
    int n, k;
    cin >> n >> k;  // 输入序列长度 n 和划分段数 k
    
    vector<int> sequence(n);
    for (int i = 0; i < n; ++i) {
    
    
        cin >> sequence[i];  // 输入序列的元素
    }

    // 使用动态规划,dp[i][j] 表示前 i 个元素划分为 j 段时的最大值
    vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));

    for (int i = 1; i <= n; ++i) {
    
    
        for (int j = 1; j <= k; ++j) {
    
    
            int maxVal = 0;
            vector<int> segment;
            for (int p = i; p >= 1; --p) {
    
    
                segment.push_back(sequence[p - 1]);
                // 在前 p-1 个元素划分为 j-1 段的基础上,加上当前划分的段的 f 值
                maxVal = max(maxVal, dp[p - 1][j - 1] + f(segment));
            }
            dp[i][j] = max(dp[i][j], maxVal);  // 更新 dp[i][j]
        }
    }

    cout << dp[n][k] << endl;  // 输出最大值

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_47895938/article/details/132307816
今日推荐