啊哈编程啊哈添柴题解:接竹竿

注:本题解仅供参考,未经过本人允许请勿复制,谢谢!!

这是本人第一次写题解,如有写的不清楚的,请在评论区反映,谢谢Thanks♪(・ω・)ノ

OK,开始正文:

1.题目详情

2.思路

显而易见,这道题是无法用暴力枚举来做的,因为从

可以看出,n与k的范围都是10^6,而暴力枚举的时间复杂度是O(n^2)的,单纯用暴力枚举是无法完成的。

所以——我就有了一个大胆的想法——动态规划!!(后来发现,这样还真行)

好了,不说了,先放一波代码:

#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;
}

别想着复制了,这代码拿不了满分

显而易见,这个代码是得不了满分的,因为,从

一看,啊哈,这时间复杂度O(n^2),咋滴可能过嘛。

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分好)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值