题解 合并 union

合并 union

Description

给出一个 1 ~ N 的序列 A ( A 1 , A 2 , ..., A N ) 。你每次可以将两个相邻的元素合并,合并后的元素权值即为 这两个元素的权值之和。求将 A 变为一个非降序列,最少需要多少步操作。

Input

输入的第一行一个整数 N ( N ≤ 5000) 。
接下来一行 N 个整数,描述序列 A 。保证序列 A 中的每个元素的值不超过 1000 。

Output

输出一行一个整数,表示最少的操作数。

Sample Input

5
9 7 5 13 15

Sample Output

1

解析

这题很明显是用DP啊啊啊!!

我们设\(f[i]\)表示将序列\(1\)~\(i\)合并的最小次数,

\(g[i]\)表示将序列\(1\)~\(i\)合后的最后一个元素的权值,

那么,从\(1\)到\(n\)枚举\(i\),

再从\(i\)~\(1\)枚举\(j\),表示将$ j\(~\)i\(合并成一个点,再添加到已经合并完后的序列\) 1\(~\)j$-\(1\)后面,

什么?你问我为什么要将$ j\(~\)i$合并成一个点?

仔细想一下,如果有一个\(k\),并且将\(j\)~\(k\)合并,再将\(k\)+$1 \(~\)i$合并后会使答案更优,

那么在枚举到\(k\)时,就会将当前情况统计一次,

而在枚举\(i\)时,当\(j\)枚举到\(k\)时,就会统计到这个答案了!!(口胡证明可能有点乱,自己画图理解下哈).

然后,我们考虑状态转移,

如果\(g[i-1]\)<=\(a[i]\)-\(a[j-1]\)(\(a\)为前缀和,表示\(i\)到\(j\)合并后的权值,整个式子就表示\(i\)到\(j\)合并后能接到\(j\)-\(1\)后面).

并且\(f[j-1]\)+\((i-j)\)<=\(f[i]\)(即次数更少,(\(i\)-\(j\))表示将\(j\)~\(i\)合并成\(1\)个点的次数),

那么我们就更新\(f[i]\)和\(g[i]\),\(g[i]\)就是\(j\)~\(i\)合成的点的权值.

那么最后,\(f[n]\)即为答案.

不清楚的看代码吧:

#include<bits/stdc++.h>
using namespace std;

inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}

int n,a[100001];
int f[100001],g[100001];

int main(){
    n=read();
    memset(f,0x3f,sizeof(f));f[0]=0;
    for(int i=1;i<=n;i++) g[i]=read();//并没什么用但也没影响,只是存一下权值
    for(int i=1;i<=n;i++) a[i]=g[i]+a[i-1];//前缀和
    for(int i=1;i<=n;i++){
        for(int j=i;j;j--){
            if(g[j-1]<=a[i]-a[j-1]){
                if(f[j-1]+i-j<f[i]){//更新
                    f[i]=f[j-1]+i-j;
                    g[i]=a[i]-a[j-1];
                }
            }
        }
    }
    printf("%d\n",f[n]);
    return 0;
}

原文地址:https://www.cnblogs.com/zsq259/p/10599249.html

时间: 2024-11-07 21:49:12

题解 合并 union的相关文章

sql语句查询结果合并union all用法_数据库技巧

--合并重复行 select * from A union select * from B --不合并重复行 select * from A union all select * from B 按某个字段排序 --合并重复行 select * from ( select * from A union select * from B) AS T order by 字段名 --不合并重复行 select * from ( select * from A union all select * from

MySQL 数据底部出现总计字样 第二种办法 纵向合并 20161103

上次在博客http://www.cnblogs.com/Mr-Cxy/p/5923375.html 我们使用了group by with rollup 函数 field自定义排序 来实现添加底部总计字样,代码很长, 再有就是我们使用纵向合并 union all 函数 ifnull sum(if())函数来实现纵向合并添加总计字样 SELECT IFNULL(f.城市,"总计") AS 城市,f.7月金额,f.8月金额,f.9月金额 FROM ( SELECT e.* FROM ( SE

练习:多表合并

多表合并 1.多表纵向合并union MariaDB [hellodb]> select from teachers union select from students; 2.交叉连接 select from students cross join select from teachers; 3.内连接inner join MariaDB [hellodb]> select * from students inner join teachers on students.teacherid=t

SPARK大数据计算BUG处理:

大数据计算BUG处理: 程序修改前资源情况: Driver : 1台 Worker : 2台 程序提交申请内存资源 : 1G内存 内存分配情况 : 1. 20%用于程序运行 2. 20%用于Shuffle 3. 60%用于RDD缓存 单条TweetBean大小 : 3k 1. 内存溢出 原因:因为程序会把所有的TweetBean查询出来并且合并(union),该操作在内存中进行.则某个campaign数据量较大时,如500W数据,则500W*10k=50G,超出内存限制. 解决方法: 先按数据量

多表之间关联查询

内连接 jion on 自连接 本表进行内连接的查询形式 外链接: 左链接 写法:select 字段 from 表1 t left join 表2 s on t.字段1 = s.字段1 where 条件 或者 作用:保证左边的表的数据全部显示,包括空的 右链接 写法 :selec 字段 from 表1 t right join 表2t.字段1=s.字段1 where 条件 作用:保证右边的表的数据全部显示,包括空的 全连接: 写法:select 字段 from 表1 t full join 表2

并查集效率测试

pre全文基础设定-----------------------------n 集合总数(即并查集个体数)m 总共操作数f find操作数Ackerman(k,n) = {n+1/k==0 | Ackerman.iter(n+1,k=k-1)(k-1,n)} / 具体定义可以看wikialpha(n) = min{k:Ackerman(k,1)>=n} 引自<算法导论> 并查集(disjoint set)有两种优化: 按秩合并(union by rank,UR) 和 路径压缩(path

MySQL 设计与开发规范

1 目的 本规范的主要目的是希望规范数据库设计与开发,尽量避免由于数据库设计与开发不当而产生的麻烦:同时好的规范,在执行的时候可以培养出好的习惯,好的习惯是软件质量的很好保证. 2 适用范围 本规划的适用人员范围包括涉及数据库设计与开发的相关技术人员. 3 术语约定 本规范采用以下术语描述: ★规则:也称为强规范是编程时必须强制遵守的原则 ★建议:编程时必须加以考虑的原则 ★说明:对此规则或建议进行必要的解释 ★示例:对此规则或建议从正.反两个方面给出 4 规范及建议 4.1 书写规范 4.1.

基于HT的CSG功能构建HTML5的3D书架

构造实体几何CSG全称Constructive solid geometry,是3D计算机图形学中构建模型的常用技术,可通过合并Union.相减Subtraction和相交Intersction的三种取集的逻辑运算,将立方体.圆柱体和棱柱等简单的基础模型,嵌套组合成更复杂三维模型. CSG的算法这些年来已有各种语言平台版本实现,C++版主流的是 http://opencsg.org/ 已有众多基于该开源类库的应用案例,JavaScript语言较早版实现 http://evanw.github.i

Python自动化开发从浅入深-语言基础(set)

set的概念有点类似于hash表,它是一个无序但不重复的元素集合.而列表.元祖和字典数据都是可以重复的. set可以方便的进行求交.差.对称差.并集等计算和比对,这在其他序列操作中则比较复杂.  如图,通过set命令就建立了一个set集合: 定义了set,我们就可以进行以下操作: 添加一个元素,如图,添加一个元素7 一次添加多个元素,如图,添加了7,9,11 删除一个元素,如图,将a中的5去掉 求set的长度,如图,求出长度为6 查看某个值是不是另一个set的元素,或不是另一个set的成员. 查