错题集
1.Longest Ordered Subsequence(最长递增子序列)
2.ISBN号码
3.开心的金明
Longest Ordered Subsequence(最长递增子序列)
这个题目的数据量不大,ʘ(n²)也过得了,但今天主要讲时间复杂度为ʘ(nlogn)的代码。
首先我们要设置一个vector<int> L{先赋字符串的第一个值}
L[i]: 长度为i+1的LIS的最小结尾
在循环n-1次,每次判断,a比目前所有LIS结尾都大,直接附上去
否则就把下一个比他大的值,换成它的值,这样保证是递增的
看完了逻辑,再让我们看一下代码:
结合代码在来理解一下
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int N, a;
cin >> N >> a;
vector<int> L{a}; // L[i]: 长度为i+1的LIS的最小结尾
for (int i = 1; i < N; i++) {
cin >> a;
if (a > L.back()) // a比目前所有LIS结尾都大,直接附上去
L.push_back(a);
else // 1 3 4 8 9 + 7, 7替换8
*lower_bound(begin(L), end(L), a) = a;
}
cout << L.size() << "\n"; // LIS长度
return 0;
}
ISBN号码
这个题目比较好理解,但我做的时候犯了一个错,把判断识别码,看成了判断整个字符串。
我们直接来看一下标程:
#include<bits/stdc++.h>
using namespace std;
const int MOD=11;
int main(){
string S;cin>>S;
int sum=0,len=S.size();
for(int i=0,j=1;i<len-1;i++){
if(S[i]=='-')continue; //分隔符就跳过
sum += (S[i]-'0')*j; //计算正确的识别码
j++;
}
sum %= MOD;
//取出输入的识别码并转化为整数类型方便计算
int ans=S[len-1]=='X'?10:S[len-1]-'0';
if(ans==sum)cout<<"Right"; //匹配成功
else {
//把原字符串的最后一位改为正确的识别码
S[len-1]=sum==10?'X':char(sum+'0');
cout<<S;
}
return 0;
}
开心的金明
这道题要重点讲一下,它是个典型的01背包,什么是01背包,就是在买时你可以选择买,或不买。所以我们来分析一下,每件物品只能购买一次,并且总价格不能超过N,可以把总价格看作背包容量,每件物品的的价格看作体积,v ,x ,j看作是价值。就好算的多了
这里就有两种解法:
1.定义F(i,j)为前i个物品,总体积不超过j的前提下,所能获得的最大价值,则显然有F(0,v)=0,并且有:F(i,v)=max(F(i−1,v),F(i−1,v−vi)+vi∗wi)括号中第二部分要求v≥vi,所求答案为 F(j,N)。
2.定义F(v)为体积不超过v的前提下所能获得的最大价值。则每次输入一个(vi,wi)之后,按照v从大到小的顺序,更新F(v)=max(F(v),F(v−vi)+viwi)即可,所求答案为F(N)。
我们来看一下代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int N, M;
cin >> N >> M;
vector<int> F(N + 1);
for (int i = 0, v, p; i < M; i++) {
cin >> v >> p;
for (int j = N; j >= v; j--) F[j] = max(F[j], F[j - v] + v * p);
}
printf("%d\n", F[N]);
return 0;
}
/* F(j,i), 总价i,[1,i]物品最大 价格*重要度为多少
F(n,i) = max(F(n,i-1), F(n-V[i], i-1) + V[i]*P[i])
i从小到大递推可以只保留v这个维度
*/
谢谢大家,欢迎点赞,收藏