• 洛谷P2300 合并神犇


    传送门啦

    分析:

    刚开始读完题后感觉很懵,怎么算都不是3,结果发现题目理解错了。题目要求的是求一个不降的序列,不是递减的(发现自己好傻)

    看明白题就好做了吧。经典的区间dp题,合并果子大家应该都做过,那个题求一个代价,这个题换成合并次数了,也差不多。

    本题要使一段序列合并成不下降序列,因为只能合并相邻的两个数,所以合并后的一个数必定是由原版序列中的一段进行数次合并得到的。考虑简单的贪心思路,对于第一个数,每次不停加入一个数直到它们的和大于第一个数停止,继续此操作,直到结束,但是这样显然是错误的,因为前面满足了条件不一定后面会最优(很简单思考懒的举例了)。

    由贪心思路引申到dp,因为是一段合并,考虑到前缀和sum[i],我们令f[i]表示到了第i个数为止所合并的次数,用一个辅助数组maxp[i]表示到了i为止合并后最大的一个数,于是得到状态转移方程:if(sum[i]-sum[j] >= maxp[j])f[i] = f[j] + j - i - 1(其中i > j)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 200005;
    
    inline int read(){
        char ch = getchar(); int f = 1 , x = 0;
        while(ch > '9' || ch < '0'){if(ch == '-') f = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,p[maxn];
    long long f[maxn],sum[maxn],maxp[maxn];
    
    int main(){
        n = read();
        for(int i=1;i<=n;i++) {
            p[i] = read();
            sum[i] = sum[i-1] + p[i];
        }
        int i,j;
        for(i=1;i<=n;i++){
            for(j=i-1;j>=0;j--)
                if(sum[i] - sum[j] >= maxp[j])
                    break;
            f[i] = f[j] + i - j - 1;
            maxp[i] = sum[i] - sum[j];
        }
        printf("%lld",f[n]);
        return 0;
    }
    顺风不浪,逆风不怂。
  • 相关阅读:
    POJ-1318(list.sort()输出不为字典序,map才是按字典序排列)
    C++ 进阶
    命令模式在MVC框架中的应用
    使用NoSQL Manager for MongoDBclient连接mongodb
    第一部分 学习函数式思维
    【剑指offer】复杂链表的复制
    Hadoop-2.4.0分布式安装手冊
    Impala中多列转为一行
    js(jquery)绑定点击事件
    hdu1243 最长公共子序列(LCS)
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/9864885.html
Copyright © 2020-2023  润新知