输入一个长度为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
#include
#include
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;
}
定义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
#include
#include
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;
}