zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
    顺风不浪,逆风不怂。
  • 相关阅读:
    silverlight 网站 iis发布
    使用PerfView诊断.Net GC的问题
    七种方法实现单例模式
    java多线程的学习之路(二)
    java多线程的学习之路(一)
    几种特殊的二叉树
    解析json字符串,把json字符串转换成Java对象
    KMP算法的理解
    常用 Git 命令清单
    Jquery.cookie.js 源码和使用方法
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/9864885.html
Copyright © 2011-2022 走看看