24/9/10 kuangbin_dp

24_9_10 完成在kuangbin专题基础dp中的5道题

还是感觉太菜了

Max Sum Plus Plus

Hdu1024

题意:即求最大m子段和,最大子段和的进阶
思路:我们设置 dp[i][j] 为选择第j个数下分成i段的最大值,因此状态转移为 dp[i][j]=max(dp[i][j1],maxdp[i1][k])(i1kn)
情况1:第 j 个数单独作为一段,但是我们并不知道第 i1 段是以什么结尾,因此是 maxdp[i1][k],情况2:第 i 个数不单独作为一段,那么由于连续性一定是和 j1 同为一段,因此是 dp[i][j1]
需要注意的是:这里显然可以用滚动数组优化,同时在枚举第i段时应当将 dp[i1]ma[i1] 赋值为-INF,原因是 i1 个元素无法分成i段,对状态转移不应该有影响

void solve() {
    while(~scanf("%lld%lld",&m,&n)) {
        init();
        for(int i = 1;i <= n;i ++ )
            scanf("%lld",&a[i]);
        for(int i = 1;i <= m;i ++ ) {
            dp[i - 1] = -INF;   //因为分成i段 i - 1个元素显然不够
            for(int j = i;j <= n;j ++ ) {
                dp[j] = a[j] + std::max(dp[j - 1],ma[j - 1]);
            }
            ma[i - 1] = -INF;   //同上
            for(int j = i;j <= n;j ++ ) {
                ma[j] = std::max(ma[j - 1],dp[j]);
            }
        }
        int ans = -INF;
        for(int i = m;i <= n;i ++ )
            ans = std::max(ans,dp[i]);
        printf("%lld\n",ans);
    }
}   

Ignatius and the Princess IV

HDU1029

水题,用数组模拟同时注意数组大小就好

Super Jumping! Jumping! Jumping!

HDU1087

题意:在数组中每次只能走比当前更大的值,求最后的最大值
思路:设置 dp[i] 为选择第i个数的最大值,显然有 dp[i]=maxdp[k]+a[i]1(ki1),类似最长不下降子序列的方式计算

void solve() {
    while((std::cin >> n) && n != 0) {
        memset(a,0,sizeof(a));
        memset(dp,0,sizeof(dp));
        for(int i = 1;i <= n;i ++ )
            std::cin >> a[i];
        for(int i = 1;i <= n;i ++ ) {
            int t = -INF;
            for(int j = 1;j <= i - 1;j ++ ) {
                if(a[i] > a[j]) t = std::max(t,dp[j]);
            }
            dp[i] = a[i] + std::max(0,t);
        }
        int ans = -INF;
        for(int i = 1;i <= n;i ++ )
            ans = std::max(ans,dp[i]);
        std::cout << ans << "\n";
    }
}   

最少拦截系统

HDU1257

前置知识:Dilworth定理(https://oi-wiki.org/math/order-theory/),即在偏序集中最长链的长度等于最小的反链覆盖数,对偶形式偏序集中最长反链的长度等于最小的链
的覆盖长度(oiwiki中有对偏序列,反链的说明)
思路:即题目求的是不上升子序列的最小覆盖数,数列在关系 是满足自反性、传递性、反对称性,因此满足偏序集,因此问题等价为最长链的长度,即求最长上升子序列

void solve() {
    while(std::cin >> n) {
        memset(a,0,sizeof(a));
        memset(dp,0,sizeof(dp));
        for(int i = 1;i <= n;i ++ )
            std::cin >> a[i],dp[i] = 1;
        for(int i = 1;i <= n;i ++ )
            for(int j = 1;j < i;j ++ ) {
                if(a[j] < a[i]) dp[i] = std::max(dp[i],dp[j] + 1);
            }
        int ans = -INF;
        for(int i = 1;i <= n;i ++ )
            ans = std::max(ans,dp[i]);
        std::cout << ans << "\n";
    }
}

免费馅饼

HDU1176

思路:是典型的数塔模型,即我们按时间高低进行排列,最后都是汇集在(0,5)这个点上,直接按数塔模型计算即可
注意:可以把所有的坐标往右移动一格,避免计算位置0和11需要特殊讨论

void solve() {
    while(std::cin >> n && n != 0) {
        // std::cin >> n;
        int t = -INF;
        memset(dp,0,sizeof(dp));
        for(int i = 1;i <= n;i ++ ) {
            int x,y;
            std::cin >> x >> y;
            dp[y][++ x] ++;
            t = std::max(t,y);
        }
        // std::cout << t << "\n";
        for(int i = t;i >= 0;i -- ) 
            for(int j = 1;j <= 11;j ++ ) {
                dp[i][j] += std::max({dp[i + 1][j - 1],dp[i + 1][j],dp[i + 1][j + 1]});
            }
        // printf("%d\n",dp[0][6]);
        std::cout << dp[0][6] << "\n";
    }
}
posted @   nnnnakosuki  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示