学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!
附上汇总贴:小猴编程C++ | 汇总-CSDN博客
【题目描述】
有n个小写字母组成的字符串,你想把它们变成字典序从小到大的顺序,但是你不能交换它们的位置,只能反转其中一些字符串。
反转第i个字符串需要消耗
c
i
c_i
ci体力值。问最小需要消耗多少体力;如果无论怎么反转都不能使这些字符串按照字典序排序,输出-1。
【输入】
第1行,1个正整数n
第2行,n个正整数
c
1
,
c
2
,
…
,
c
n
c_1,c_2,\dots,c_n
c1,c2,…,cn
第3 - n+2行,第i+2行是第i个字符串
s
i
s_i
si
【输出】
输出最小消耗体力。如果无论怎么反转都不能使这些字符串按照字典序排序,输出-1。
【输入样例】
3
1 3 1
aa
ba
ac
【输出样例】
1
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n, c[N];
string s[N], r[N];
long long dp[N][2];
int main()
{
cin >> n;
for (int i=1; i<=n; i++) cin >> c[i];
for (int i=1; i<=n; i++) {
cin >> s[i];
r[i] = s[i]; // 复制r字符串
reverse(r[i].begin(), r[i].end()); // 使用reverse函数反转字符串
}
memset(dp, 0x3f, sizeof(dp)); // 序列dp,初始值设为无穷大
dp[1][0] = 0; // 定义初始值,如果不反转,则为0
dp[1][1] = c[1]; // 如果反转,则为c[1]
for(int i=2; i<=n; i++) { // 从第2个字符串开始枚举
if (s[i-1]<=s[i]) { // 参考样例分析,列出递推式
dp[i][0] = min(dp[i][0], dp[i-1][0]);
}
if (r[i-1]<=s[i]) {
dp[i][0] = min(dp[i][0], dp[i-1][1]);
}
if (s[i-1]<=r[i]) {
dp[i][1] = min(dp[i][1], dp[i-1][0] + c[i]);
}
if (r[i-1]<=r[i]) {
dp[i][1] = min(dp[i][1], dp[i-1][1] + c[i]);
}
}
long long ans = min(dp[n][0], dp[n][1]); // 最后结果可以选反转或不反转,
if (ans<dp[0][0]) printf("%lld\n", ans); // dp[0][0]为无穷大,如果ans不是这个值,说明有结果
else printf("-1\n"); // 否则输出-1,表示无解
return 0;
}
【运行结果】
3
1 3 1
aa
ba
ac
1