注:本题解仅供参考,未经过本人允许请勿复制,谢谢!!
这是本人第一次写题解,如有写的不清楚的,请在评论区反映,谢谢Thanks♪(・ω・)ノ
OK,开始正文:
1.题目详情
2.思路
显而易见,这道题是无法用暴力枚举来做的,因为从
可以看出,n与k的范围都是,而暴力枚举的时间复杂度是的,单纯用暴力枚举是无法完成的。
所以——我就有了一个大胆的想法——动态规划!!(后来发现,这样还真行)
好了,不说了,先放一波代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cctype>
#define ll long long
#define sll static long long
#define db double
#define str string
#define sint static int
#define lint inline int
#define lb inline bool
#define lll inline long long
#define cint const int
#define cdb const double
#define cll const long long
using namespace std;
sll n, m, h[1000010], dp[1000001], sum[1000010], a[1000010];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> h[i]; //输入花色
for (int i = 1; i <= n; i++) {
cin >> a[i]; //点数
sum[i] = sum[i - 1] + a[i]; //看懂的都看得懂
}
dp[1] = 0; //初始状态
for (int i = 2; i <= n; i++) { //很明显,这是个01背包
dp[i] = dp[i - 1]; //这里做了一个小小的优化
for (int j = i - 1; j >= 1; j--) { //第二层循环从后往前推
if (h[i] == h[j]) { //如果两张牌花色相同
dp[i] = max(dp[i], dp[j - 1] + sum[i] - sum[j - 1]); //状态转移~~~
}
}
}
cout << dp[n]; //无需多言,dp[n]就是状态属性
return 0;
}
别想着复制了,这代码拿不了满分
显而易见,这个代码是得不了满分的,因为,从
一看,啊哈,这时间复杂度,咋滴可能过嘛。
3.正确代码
好了,看完错误代码,咱们也该看看正确的了,废话不多说,上代码!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cctype>
#define ll long long
#define sll static long long
#define db double
#define str string
#define sint static int
#define lint inline int
#define lb inline bool
#define lll inline long long
#define cint const int
#define cdb const double
#define cll const long long
using namespace std;
sll n, m, h[1000010], dp[1000001], sum[1000010], a[1000010], t[1000100];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> h[i];
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
memset(t, -0x3f, sizeof t); //t数组初始化
for (int i = 1; i <= n; i++) {
dp[i] = max(dp[i - 1], sum[i] + t[h[i]]); //进行数组优化
t[h[i]] = max(t[h[i]], dp[i - 1] - sum[i - 1]); //推导可得
}
cout << dp[n];
return 0;
}
4.优化
论五十二分代码是怎么优化成一百分代码的~
首先,我们看看两个代码的不同:
旧:
新:
这个地方,我们新定义了一个t数组,把
for(int j=i-1;j>=1;j--){
if(h[i]==h[j])
dp[i]=max(dp[i],dp[j-1]+sum[i]-sum[j-1]);
}
通过找到不变量->sum[i]来完成优化
(才不是我太懒不想写推导过程了呢)
5.总结
这道题是一个较为复杂的动态规划问题,动归新手可能不太好掌握,建议吧01背包吃透了再来。但是,一定要记住,如果你在考试中遇到类似的题,实在没有思路,记得不要硬钢,用枚举做。(毕竟52分代码总比0分好)