(

宋

体

字

看

起

来

真

舒

服

)

_{_{(宋体字看起来真舒服)}}

(宋体字看起来真舒服)​​

题

面

(

洛

谷

翻

译

)

题面_{_{(洛谷翻译)}}

题面(洛谷翻译)​​

给定

n

n

n个不降的数组。
有一个值

a

n

s

ans

ans,初始为

0

0

0
你需要进行如下操作

k

k

k次:

1.选择一个数组
2.把

a

n

s

ans

ans加上数组的第一个元素。
3.把数组的第一个元素删除。

请求出

a

n

s

ans

ans最大是多少。

所有数组的元素总个数

≤

1

0

6

,

n

,

k

≤

3000

\leq 10^6,n,k\leq 3000

≤106,n,k≤3000

输

入

(

笔

者

亲

自

翻

译

)

输入_{_{(笔者亲自翻译)}}

输入(笔者亲自翻译)​​

第一行包含两个整数

n

n

n and

k

k

k (

1

≤

n

,

k

≤

3
 

000

1 \le n, k \le 3\,000

1≤n,k≤3000 ): 分别是数组和操作的数量。

接下来的

n

n

n 行每一行包含一个数组。 每一行的第一个整数是

t

i

t_i

ti​ (

1

≤

t

i

≤

1

0

6

1 \le t_i \le 10^6

1≤ti​≤106 ): 第

i

i

i 个数组的大小。 后面

t

i

t_i

ti​ 个整数

a

i

,

j

a_{i, j}

ai,j​ (

0

≤

a

i

,

1

≤

…

≤

a

i

,

t

i

≤

1

0

8

0 \le a_{i, 1} \le \ldots \le a_{i, t_i} \le 10^8

0≤ai,1​≤…≤ai,ti​​≤108 ) 给出了第

i

i

i 个数组。

保证

k

≤

∑

i

=

1

n

t

i

≤

1

0

6

k \le \sum\limits_{i=1}^n t_i \le 10^6

k≤i=1∑n​ti​≤106。

样

例

样例

样例

i

n

p

u

t

input

input

3 3
2 5 10
3 1 2 3
2 1 20
o

u

t

p

u

t

output

output

26

题

解

题解

题解

转换一下模型,相当于一个背包问题,这个不用我多说了吧。

我们会发现一个结论:最后的最优操作一定是把一些数组全选完,最多一个数组只选部分。

S

t

e

p
  

1
  

证

明

结

论

Step\;1\;证明结论

Step1证明结论

我们要证这个结论,实际上要证最优操作不存在两个只选了部分的数组:

为了方便证明,我们定义两个数组总和相等的时候,两数组选的数量相差更大的更优

其实很简单,如果存在这么两个数组选了部分:

那么以下两种情况肯定更优:

  1. a

    i

    ,

    x

    ≥

    a

    j

    ,

    y

    ⇒

    a

    i

    ,

    x

    +

    1

    ≥

    a

    j

    ,

    y

    :

    a_{i,x} ≥ a_{j,y} \Rightarrow a_{i,x+1} ≥ a_{j,y}:

    ai,x​≥aj,y​⇒ai,x+1​≥aj,y​:

  2. a

    i

    ,

    x

    ≤

    a

    j

    ,

    y

    ⇒

    a

    j

    ,

    y

    +

    1

    ≥

    a

    i

    ,

    x

    :

    a_{i,x} ≤ a_{j,y} \Rightarrow a_{j,y+1} ≥ a_{i,x}:

    ai,x​≤aj,y​⇒aj,y+1​≥ai,x​:

而这两种情况已经包含全集了(

a

i

,

x

≥

a

j

,

y

a_{i,x} ≥ a_{j,y}

ai,x​≥aj,y​ 和

a

i

,

x

≤

a

j

,

y

a_{i,x} ≤ a_{j,y}

ai,x​≤aj,y​),所以充分证明了 两个数组都没选完,在中间稳定 的情况是不存在的,因此最多就只有其中一个选完了,另一个没选完的情况。

S

t

e

p
  

2
  

利

用

结

论

Step\;2\;利用结论

Step2利用结论

这个结论怎么利用呢?

相当于我们如果确定某一个数组是只选部分的那一个,那么其他的数组就降维了、变成一个数了、一个物品了!

于是我们可以先把其他数组假设成只有一个数,然后把背包跑出来,最后暴力枚举只选部分的那个数组具体选几个。

那么,每一个数组一开始都有一个空的背包dp数组,表示该数组只选部分的情况下其他数组放进来处理的背包。但是这样还是

O

(

n

2

k

)

O(n^2k)

O(n2k) 的过不了。

我们可以想想怎么优化。我们发现每个数组

i

i

i 整个考虑会对

[

1

,

i

−

1

]

∪

[

i

+

1

,

n

]

[1,i-1]∪[i+1,n]

[1,i−1]∪[i+1,n] 内的其他数组的背包有贡献,这是两个区间,因此我们可以用线段树分治优化它,

这样一来每个数组就要对

l

o

g

n

logn

logn 个区间有贡献,而每次贡献是一次

O

(

m

)

O(m)

O(m) 的背包更新,时间复杂度

O

(

n

m

l

o

g

n

)

O(nmlogn)

O(nmlogn)。

最后,由于每个数组挂的区间有特殊性,可以不用真的建一棵线段树,直接判断挂在当前区间的数组有哪些就行了。

C

O

D

E

CODE

CODE

#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 3005
#define LL long long
#define DB double
#define ENDL putchar('\n')//#define lowbit(x) ((-x)&(x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k,sq;
LL dp[100][MAXN];
bool f[100][MAXN];
vector<LL> a[MAXN];
int b[MAXN];
LL ans = 0;
void solve(int l,int r,int de) {
memcpy(dp[de],dp[de-1],sizeof(dp[de]));
memcpy(f[de],f[de-1],sizeof(f[de]));
for(int i = 1;i <= n;i ++) {
if(i == l) {
i = r;continue;
}
if(!f[de][i]) {
f[de][i] = 1;
int tp = a[i][0];
for(int j = m;j >= tp;j --) {
dp[de][j] = max(dp[de][j],dp[de][j-tp] + a[i][tp]);
}
}
}
if(l < r) {
int mid = (l + r) >> 1;
solve(l,mid,de+1);solve(mid+1,r,de+1);
return ;
}
else {
int tp = a[l][0];
ans = max(ans,dp[de][m]);
for(int i = 1;i <= tp && i <= m;i ++) {
ans = max(ans,dp[de][m-i] + a[l][i]);
}
}
return ;
}
int main() {
n = read();m = read();
for(int i = 1;i <= n;i ++) {
s = read();
LL sm = 0;
a[i].push_back(s);
while(s --) {
sm += read();
a[i].push_back(sm);
}
}
solve(1,n,1);
printf("%lld\n",ans);
return 0;
}

CF1442D Sum (动态规划,线段树分治)的更多相关文章

  1. 【洛谷P4319】 变化的道路 线段树分治+LCT

    最近学了一下线段树分治,感觉还蛮好用... 如果正常动态维护最大生成树的话用 LCT 就行,但是这里还有时间这一维的限制. 所以,我们就把每条边放到以时间为轴的线段树的节点上,然后写一个可撤销 LCT ...

  2. LOJ2312 LUOGU-P3733「HAOI2017」八纵八横 (异或线性基、生成树、线段树分治)

    八纵八横 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路的两端都是城市(可能两端是同一个 ...

  3. BZOJ_1672_[Usaco2005 Dec]Cleaning Shifts 清理牛棚_动态规划+线段树

    BZOJ_1672_[Usaco2005 Dec]Cleaning Shifts 清理牛棚_动态规划+线段树 题意:  约翰的奶牛们从小娇生惯养,她们无法容忍牛棚里的任何脏东西.约翰发现,如果要使这群 ...

  4. loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

    题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...

  5. BZOJ.4184.shallot(线段树分治 线性基)

    BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...

  6. BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)

    BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...

  7. 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)

    LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...

  8. bzoj4025二分图(线段树分治 并查集)

    /* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...

  9. BZOJ3237:[AHOI2013]连通图(线段树分治,并查集)

    Description Input Output Sample Input 4 5 1 2 2 3 3 4 4 1 2 4 3 1 5 2 2 3 2 1 2 Sample Output Connec ...

随机推荐

  1. 【python】tile函数简单介绍

    转:https://blog.csdn.net/april_newnew/article/details/44176059格式:tile(A,reps)* A:array_like* 输入的array ...

  2. 多路分支、for循环

    多路分支 多路分支也叫做switch语句,它的格式: switch (控制表达式){ case 条件: 输出....} switch 可以看成一种跳转,每当我们满足跳转就会跳转到响应的位置,接下我们写 ...

  3. C语言 - 基础数据结构和算法 - 单向链表

    听黑马程序员教程<基础数据结构和算法 (C版本)>,照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友可 ...

  4. JS:表达式

    js代码的形式: 1.直接量 2.表达式 3.语句 1; "a"; true; null; var a; function fn(){}; b; var c = 20; var f ...

  5. JS:Boolean

    Boolean数据类型: 有两个值:true false Boolean会把不是Boolean的值变为Boolean值 var a = 1; var b = true; var c = 0; var ...

  6. GitLab、Jenkins结合构建持续集成(CI)环境

    1 持续集成 概述及运行流程 1.1 持续集成概述 持续集成概述:持续集成(Continuous integration)持续集成是指开发者在代码的开发过程中,可以频繁的将代码部署集成到主干,并迚程自 ...

  7. 互联网研发效能之去哪儿网(Qunar)核心领域DevOps落地实践

    本文从业务目标角度出发,确定了开源+自建模式搭建 Qunar 研发工具链整体生态:通过 APPCODE 打通工具链,流程规范化自动化:多种手段+发布门禁助力质量提升:建立应用画像确定运维最小单元,可发 ...

  8. 问题:CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://mirrors.tuna.tsinghua.edu.cn/anaconda/pk

    使用anaconda安装tensorflow (windows10环境) 遇到的问题:CondaHTTPError: HTTP 000 CONNECTION FAILED for url <ht ...

  9. java--运算符和表达式

    运算符:就是对常量或者遍历进行操作的符号: 表达式:用运算符把常量或者变量连接起来符合java语法的式子称为表达式,不同运算符连接的表达式体现的是不同类型的表达式. 一.算术运算符 1.使用%运算符: ...

  10. 查询postgresql表结构和索引

    通过系统数据字典查询表结构 selectcol.table_schema,col.table_name,col.ordinal_position,col.column_name,col.data_ty ...