题目描述
大科学家dddd最近在研究转基因白菜,白菜的基因序列由一串大写英文字母构成,dddd经过严谨的推理证明发现,只有当白菜的基因序列呈按位非递减形式时,这株白菜的高附加值将达到最高,于是优秀的dddd开始着手修改白菜的基因序列,dddd每次修改基因序列的任意位需要的代价是11,dddd想知道,修改白菜的基因序列使其高附加值达到最高,所需要的最小代价的是多少。
输入描述:
第一行一个正整数n(1≤n≤1000000)
第二行一个长度为n的字符串,表示所给白菜的基因序列
保证给出字符串中有且仅有大写英文字母
输出描述:
输出一行,表示最小代价
示例1
输入
5
ACEBF
输出
1
解析
这题的本质就是求最长的非递减子序列,其余的字符需要进行修改。因此有两种方法
dp
对于字符
s
[
i
]
s[i]
s[i],他只能接在一个字典序小于等于
s
[
i
]
s[i]
s[i]的后面,因此我们很容易得到转移方程
我们设
c
h
a
r
I
n
d
e
x
[
j
]
charIndex[j]
charIndex[j]为上一个字符
j
j
j的下标
d
p
[
i
]
dp[i]
dp[i]为考虑前
i
i
i个字符并且以第
i
i
i个字符结尾的的最长子序列长度
d
p
[
i
]
=
m
a
x
(
d
p
[
i
]
,
d
p
[
c
h
a
r
I
n
d
e
x
[
j
]
]
)
(
j
<
s
[
i
]
)
dp[i]=max(dp[i],dp[ charIndex[j]])(j<s[i])
dp[i]=max(dp[i],dp[charIndex[j]])(j<s[i])
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000005;
char s[N];
int charIndex[26];//存储上一个字符的下标
int dp[N];//dp[i] 表示[1,i]最小代价
int main() {
int n ;
scanf("%d%s",&n,s+1);
int res=0,mx=0;
for(int i=1;i<=n;i++){
int a=s[i]-'A';
for(int j=0;j<=a;j++){
dp[i]=max(dp[i],dp[charIndex[j]]+1);
}
mx=max(dp[i],mx);
charIndex[a]=i;
}
cout<<n-mx;
}
二分+贪心
同样也是找最长非递减子序列,我们可以用一个简单的贪心思维去考虑,最长的非递减子序列应该是越紧凑越好,
以输入序列 [0, 8, 4, 12, 2] 为例:
第一步插入 0,d = [0]d=[0];
第二步插入 8,d = [0, 8]d=[0,8];
第三步插入 4,d = [0, 4]d=[0,4];
第四步插入 12,d = [0, 4, 12]d=[0,4,12];
第五步插入 2,d = [0, 2, 12]d=[0,2,12]。
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int r[1000010];
int len = 1;
int main(){
cin>>n;
cin>>s;
r[1] = s[0] - 'A';
for(int i = 1; i < n ;i++){
int pos = upper_bound(r + 1, r + len + 1, s[i] - 'A') - r;//大于s[i]的下标
r[pos] = s[i] - 'A';//
len = max(len, pos);
}
cout<<n - len<<endl;
return 0;
}