小欧有一个字符串,她要从字符串的开头走到字符串的结尾,初始时小欧在字符串开头。
她每次可以花费"两个位置字母 ASCII 码值之差的绝对值"的代价走到下一个位置,或花费 "2 的位置距离减一次方"的代价走到下一个与此位置字母相同的位置。
例如字符串 aba,小欧可以先花费 1 的代价从 'a' 走到 'b' 再花费 1 的代价从 'b' 走到 'a' ,也可以直接花费
求小欧从字符串开头走到结尾需要花费的最小代价。
第一行输入一个整数。
第二行输入一个长度为的仅由小写字母组成的字符串。
输出一个整数表示答案。
3 aba
2
如题目描述。
n = int(input()) chs = input() pos = 0 cost = [0] * n for i in range(1,n): lft = cost[i-1] + abs(ord(chs[i]) - ord(chs[i-1])) idx = chs[:i].rfind(chs[i]) if idx != -1: rgt = cost[idx] + 2**(i-1-idx) else: rgt = 10**6 cost[i] = min(lft, rgt) print(cost[-1])
对于每个位置i:
如果直接从i-1位置走过来:
如果存在前面相同字符的位置k:
使用一个数组记录每个字符出现的所有位置,方便快速查找前面相同字符的位置
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
string s;
cin >> s;
s = "&" + s;
vector<long long> dp(n + 1);
vector<vector<int>> val(28, vector<int>(0));
for (int i = 1; i <= n; i++) {
val[s[i] - 'a' + 1].push_back(i);
}
int cnt[28] = {0};
dp[1] = 0;
cnt[s[1] - 'a' + 1]++;
for (int i = 2; i <= n; i++) {
if (cnt[s[i] - 'a' + 1] == 0)
dp[i] = dp[i - 1] + abs(s[i] - s[i - 1]);
else {
long long k = val[s[i] - 'a' + 1][cnt[s[i] - 'a' + 1] - 1];
if ((i - k - 1) <= 32)
dp[i] = min(dp[k] + (1ll << (i - k - 1)), dp[i - 1] + abs(s[i] - s[i - 1]));
else dp[i] = dp[i - 1] + abs(s[i] - s[i - 1]);
}
cnt[s[i] - 'a' + 1]++;
}
cout << dp[n] << endl;
}
n = int(input())
s = input()
if n == 1:
print(0)
else:
dp = [float('+inf')] * n
dp[0] = 0
for i in range(1,n):
for j in range(max(0,i-9),i):
if s[j] == s[i]:
dp[i] = min(dp[i],dp[j]+2**(i-j-1))
dp[i] = min(dp[i],dp[i-1]+abs(ord(s[i])-ord(s[i-1])))
print(dp[-1]) 可以利用条件优化。指数函数增长很快。2**(x-1)>25*x的最小x为9。复杂度O(N)。大约扫了10次表格。
n = int(input())
s = input()
n = len(s)
dp = [float('inf')] * n
dp[0] = 0
dmap = {}
dmap.setdefault(s[0],[0])
for i in range(1,n):
if s[i] not in dmap:
dmap.setdefault(s[i],[i])
dp[i] = min(dp[i],dp[i-1]+abs(ord(s[i])-ord(s[i-1])))
else:
tmp = dp[i-1]+abs(ord(s[i])-ord(s[i-1]))
for j in dmap[s[i]]:
dp[i] = min(dp[i],tmp,dp[j]+pow(2,i-j-1))
dmap[s[i]].append(i)
# print(dmap)
# print(dp)
print(dp[-1]) from collections import deque
n = int(input())
s = input()
n = len(s)
dp = [float('inf')] * n
dp[0] = 0
dmap = {}
# 使用 deque 来优化状态转移
dmap.setdefault(s[0], deque([0]))
for i in range(1, n):
dp[i] = dp[i - 1] + abs(ord(s[i]) - ord(s[i - 1]))
# 如果之前有相同的字符出现过
if s[i] in dmap:
# 通过 deque 来保持可能的最小值位置
while dmap[s[i]] and dp[dmap[s[i]][0]] + pow(2, i - dmap[s[i]][0] - 1) >= dp[i]:
dmap[s[i]].popleft()
for j in dmap[s[i]]:
dp[i] = min(dp[i], dp[j] + pow(2, i - j - 1))
dmap.setdefault(s[i], deque()).append(i)
print(dp[-1])