博主学习本题的经过嘤嘤嘤:

7.22 : 听学长讲(一知半解)——自己推(推不出来)——网上看题解——以为自己会了(网上题解是错的)——发现错误以后又自己推(没推出来)——给学长发邮件——得到正确解法——按着学长思路又推一遍——最后理解

(前后的“学长”不是同一个人)

7.23 : 写出代码,完善细节。

(建议改成:西   天   取   经)

首先,网上对于这道题的题解绝大部分是错误的!(比如洛谷上的部分题解)

用LIS做是不行的

玄学贪心是不行的

dp转移方程不能自圆其说是不行的

即使是AC代码也不一定是正确的(2009年的省选,数据太太太太太太太太太太太太太太水了嘤嘤嘤)

废话说完了

~~~~~~~~~~~~~~~嘤嘤嘤来自蒟蒻OIerOrzer的分割线啦嘤嘤嘤~~~~~~~~~~~~~~~~

以下为正文部分嘤嘤嘤:

考虑把一个数列分成两个集合,有a[i]的为一个集合,没有a[i]的为一个集合~

我们定义状态转移方程dp[i][j]表示对于前i个数,有a[i]的集合的长度为j,没有a[i]的集合的最后一个数的最小值为dp[i][j](神仙定义)

也就是说,现在有两个集合,其中一个有a[i],另一个没有a[i]。尝试把a[i+1]放到其中一个集合中。

1.尝试把a[i+1]放到有a[i]的集合当中。那么需要满足的先决条件就是:a[i+1]>a[i].

此时更新dp[i+1][j+1](因为把a[i]放到长度为j的集合中,于是长度++)此时没有a[i+1]的集合同时也是没有a[i]的集合,换句话来说,这个转移对没有a[i]的集合是没有改变的,所以,dp[i+1][j+1]可以直接由dp[i][j]继承过来。

2.尝试把a[i+1]放到没有a[i]的集合当中。那么需要满足的先决条件就是:a[i+1]>dp[i][j].

此时更新dp[i+1][i-j+1](原来没有a[i]的集合的长度为(i-j),把a[i+1]放进去,长度++)既然把a[i+1]放到了没有a[i]的集合中,那么,没有a[i+1]的集合的最后一个数就是a[i],于是,用a[i]去更新dp[i+1][i-j+1];

(真绕啊嘤嘤嘤)

上代码嘤嘤嘤:

 1 #include <bits/stdc++.h>
2 using namespace std;
3 const int maxn=2000+10;
4 int dp[maxn][maxn],a[maxn];
5 int n,m;
6 void Solve(){
7 scanf("%d",&m);
8 while(m--){
9 scanf("%d",&n);
10 memset(dp,0x3f,sizeof(dp));
11 memset(a,0x3f,sizeof(a));
12 for(int i=1;i<=n;++i) scanf("%d",&a[i]);
13 dp[1][1]=-1;//因为数据中可能有0,因此不能初始化为0;
14 for(int i=1;i<=n;++i){
15 for(int j=1;j<=i;++j){
16 if(a[i+1]>a[i]) dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]);
17 if(a[i+1]>dp[i][j]) dp[i+1][i-j+1]=min(dp[i+1][i-j+1],a[i]);
18 }
19 }
20 if(dp[n][n/2]>1e8) printf("No!\n");
21 //没有更新,说明不能将原序列合法地平分成两部分,就输出No;
22 else printf("Yes!\n");
23 }
24 }
25 int main(){
26 Solve();
27 return 0;
28 }

完结撒花嘤嘤嘤~(然而并没有)

上辈子的题了(大雾)(所以这就是火星水吗)

但是在解决上一道题后会发现对于这道题会有不一样的理解~~~

我们先定义dp[i][j]表示小烈1走到i,小烈2走到j时的最大收益。且默认小烈1始终在小烈2前面,且前j个已经被送完。

换句话来说,其实根本没有小烈1和小烈2(只是我们yy出来的)或者说,并不是划分了“小烈1”和“小烈2”这两个抽象的概念,划分的应该是“送了a[i]的小烈”和“没有送a[i]的小烈”!

(woc这不就是上一道题吗,太像了好叭)

现在我们换一种表达方式来定义dp[i][j]:

dp[i][j]表示前i个客人,没有送过a[i]的小烈最后一个送的是a[j]时的最大收益。

默认j小于i,且前j个一定已经送过了(如果前j个有没有送过的,那就不合法了,因为两个小烈不能回头)

现在考虑a[i+1]由谁送。

1.由送了a[i]的小烈送。所以,没有送a[i]的小烈同样没有送a[i+1]。也就是说,这个转移完成后,没有送a[i]的小烈原来在j,现在还是在j,没有变化。

所以用(dp[i][j]+a[i]*a[i+1])更新(dp[i+1][j])。

2.由没有送a[i]的小烈送。所以,送了a[i]的小烈没有送a[i+1]。也就是说,没有送a[i+1]的小烈最后一个送的是a[i]!

所以用(dp[i][j]+a[j]*a[i+1])更新(dp[i+1][i]).

(和刚才那个一样绕嘤嘤嘤)

上代码:

 1 #include <bits/stdc++.h>
2 using namespace std;
3 const int maxn=2500+10;
4 int dp[maxn][maxn],a[maxn],ans;
5 void Solve(){
6 int n;scanf("%d",&n);
7 for(int i=1;i<=n;++i) scanf("%d",&a[i]);
8 for(int i=1;i<=n;++i){
9 for(int j=0;j<i;++j){//j的范围要搞清楚哦;
10 dp[i+1][j]=max(dp[i+1][j],dp[i][j]+a[i]*a[i+1]);
11 dp[i+1][i]=max(dp[i+1][i],dp[i][j]+a[j]*a[i+1]);
12 }
13 }
14 for(int i=0;i<n;++i) ans=max(ans,dp[n][i]+a[i]*a[n]);
15 /*现实中的小烈是从1走到n,又从n回去,在dp方程里面我们把一个小烈拆成了两个,
16 其中一个表示现实中正向走的部分,另一个表示现实中反向走的部分(但是令这一个
17 反向走的小烈反过来走,就是正着走)也就是说,当现实中小烈走到n,开始返回的
18 时候,a[n]与dp方程中定义的小烈2经过的最后一个a[i](也就是反着走的第一个
19 a[i])是要产生一个值的,而这个值要加到答案里面才能得到最终结果*/
20 printf("%d",ans);
21 }
22 int main(){
23 Solve();
24 return 0;
25 }

嘤嘤嘤

完结撒花花!!!

[HNOI2009]双递增序列(洛谷P4728)+小烈送菜(内部训练题)——奇妙的dp的更多相关文章

  1. 【BZOJ1489】[HNOI2009]双递增序列(动态规划)

    [BZOJ1489][HNOI2009]双递增序列(动态规划) 题面 BZOJ 洛谷 题解 这\(dp\)奇奇怪怪的,设\(f[i][j]\)表示前\(i\)个数中,第一个数列选了\(j\)个数,第二 ...

  2. 小烈送菜——奇怪的dp

    小烈送菜 题目描述 小烈一下碰碰车就被乐满地的工作人员抓住了.作为扰乱秩序的惩罚,小烈必须去乐满地里的"漓江村"饭店端盘子. 服务员的工作很繁忙.他们要上菜,同时要使顾客们尽量高兴 ...

  3. 线性DP之小烈送菜

    小烈送菜 小烈一下碰碰车就被乐满地的工作人员抓住了.作为扰乱秩序的惩罚,小烈必须去乐满地里的"漓江村"饭店端盘子. 服务员的工作很繁忙.他们要上菜,同时要使顾客们尽量高兴.一位服务 ...

  4. 方格取数(简单版)+小烈送菜(不知道哪来的题)-----------奇怪的dp增加了!

    一.方格取数: 设有N*N的方格图(N<=20),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0. 某人从图的左上角的A(1,1) 点出发,可以向下行走,也可以向右走,直到到达右下 ...

  5. 【题解】洛谷P1373 小a和uim之大逃离(坐标DP)

    次元传送门:洛谷P1373 思路 设f[i][j][t][1/0]表示走到(i,j)时 小a减去uim的差值为t 当前是小a取(0) uim取(1) 那么转移就很明显了 f[i][j][t][]=(f ...

  6. P4728 [HNOI2009]双递增序列

    题意 这个DP状态有点神. 首先考虑一个最暴力的状态:\(f_{i,j,k,u}\)表示第一个选了\(i\)个,第二个选了\(j\)个,第一个结尾为\(k\),第二个结尾为\(u\)是否可行. 现在考 ...

  7. [luogu4728 HNOI2009] 双递增序列 (dp)

    传送门 Solution 前几天刚做了类似题,这种将一个序列拆分为两个单调序列的题一般都是设\(dp[i]\)表示i为一个单调序列的末尾时,另一个序列的末尾是多少 然后应用贪心的思想,在这道题中就是让 ...

  8. [HNOI2009]双递增序列(动态规划,序列dp)

    感觉这个题还蛮难想的. 首先状态特别难想.设\(dp[i][j]\)表示前i个数,2序列的长度为j的情况下,2序列的最后一个数的最小值. 其中1序列为上一个数所在的序列,2序列为另外一个序列. 这样设 ...

  9. [HNOI2009]双递增序列

    不难发现本题贪心是不好做的,可以考虑 \(dp\). 首先的一个想法就是令 \(dp_{i, j, k, l}\) 表示当前选到第 \(i\) 个位置,当前第一个序列选了 \(j\) 个数,当前第一个 ...

随机推荐

  1. 一文读懂Redis

    目录结构如下: 简介 Redis是一个高性能的key-value数据库.Redis对数据的操作都是原子性的. 优缺点 优点: 基于内存操作,内存读写速度快. Redis是单线程的,避免线程切换开销及多 ...

  2. vue 输入框内容控制

    只能输入数字 <el-input onkeyup="value=value.replace(/[^\d]/g,'')" v-model.number="a" ...

  3. 网络前置任务(Pretext task)和下游任务(downstream tasks)

    Pretext task 可以理解为是一种为达到特定训练任务而设计的间接任务. 比如,要训练一个网络来对 ImageNet 分类,可以表达为 $f_{\theta}(x): x \rightarrow ...

  4. 洛谷P1309——迷宫(傻瓜DFS)

    题目背景 迷宫 [问题描述] 给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过.给定起点坐标和 终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案.在迷宫 中移动有上下 ...

  5. HTML+CSS设计个人主页

    在个人主页的设计中,我采用了圣代布局和div分块.效果图如下: <!DOCTYPE html> <html lang="en"> <head> ...

  6. 利用 Nginx 搭建小型的文件服务器

    利用 Nginx 搭建小型的文件服务器 1.查看 Nginx 配置 android@localhost:/etc/nginx/conf.d$ nginx -hnginx version: nginx/ ...

  7. css 限制字数

    text-overflow: ellipsis; overflow: hidden; 不过需设置宽高

  8. (原创)一步步优化业务代码之——从数据库获取DataTable并绑定到List<Class>

    一,前言 现实业务当中,有一个很常见的流程:从数据库获取数据到DataTable,然后将DataTable绑定到实体类集合上,一般是List<Class>,代码写起来也简单:遍历+赋值就可 ...

  9. Spring Cloud Gateway 没有链路信息,我 TM 人傻了(中)

    本系列是 我TM人傻了 系列第五期[捂脸],往期精彩回顾: 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了 这个大表走索引字段查询的 SQL 怎么就成全扫描了,我TM人傻了 获取异 ...

  10. jQuery has been removed

    jQuery has been removed, 新的项目不要用jQuery了 这些问题都已经有了解决方案 * $()选择器, * $.ajax, * $dom.on("click" ...