dp学习笔记(各种dp,比较杂)
中文题意不多解释了。
建一个二维dp数组,dp[ i ][ j ]表示第 i 秒落在 j 处一个馅饼。我们需要倒着DP,为什么呢,从 0秒,x=5处出发,假如沿数组正着往下走,终点到哪里我们是不知道的,沿这个路线能最大值,下一秒就未必是最大值。但是我们知道起点,所以我们从终点开始走,走到dp[ 0 ][ 5 ]为止。由于这个总路线存在着诸多未知情况,但是有一点我们可以确定:
i , j
i+1,j-1 i+1,j i+1,j+1
对于dp[ i ][ j ]这个点,想走到下一步,肯定要加上下一步的更大的值,这个东西是不会变的。所以从最后时间点max-1(其实从max也是可以过的)开始往上走,每次取 i ,j 的下一行三个数的最大值,再加上i,j就可以了。得到方程:
dp【i】【j】+= max(dp【i+1】【j-1】,dp【i+1】【j】,dp【i+1】【j+1】);
最后输出dp[0][5]这个起点就可以了。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1e5+;
int dp[maxn][];
int main()
{
int n;
while(scanf("%d",&n))
{
if(n==)
break;
memset(dp,,sizeof(dp));
int t,x;
int maxx=-;
for(int i= ;i <= n;i++)
{
scanf("%d%d",&x,&t);
dp[t][x]++;
if(t>maxx)
maxx=t;
}
for(int i=maxx-;i>=;i--)
{
for(int j=;j<=;j++)
{
int mid = max(dp[i+][j-],dp[i+][j]);
dp[i][j]+=max(mid,dp[i+][j+]);
}
}
printf("%d\n", dp[][]);
}
}
Alex doesn't like boredom. That's why whenever he gets bored, he comes up with games. One long winter evening he came up with a game and decided to play it.
Given a sequence a consisting of n integers. The player can make several steps. In a single step he can choose an element of the sequence (let's denote it ak) and delete it, at that all elements equal to ak + 1and ak - 1 also must be deleted from the sequence. That step brings ak points to the player.
Alex is a perfectionist, so he decided to get as many points as possible. Help him.
Input
The first line contains integer n (1 ≤ n ≤ 105) that shows how many numbers are in Alex's sequence.
The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 105).
Output
Print a single integer — the maximum number of points that Alex can earn.
Examples
2
1 2
2
3
1 2 3
4
9
1 2 1 3 2 2 2 2 3
10
Note
Consider the third test example. At first step we need to choose any element equal to 2. After that step our sequence looks like this [2, 2, 2, 2]. Then we do 4 steps, on each step we choose any element equals to 2. In total we earn 10 points.
题意:删除ak,那么这个数组所有的ak+1,ak-1都被删除,同时得到ak分。求能得到的最大分数。
对每个数进行了桶排序num。这样对后面的差大于1的数没有后效性。。从0位置开始向右消去,那么要消除一个数 i ,如果i-1被消去,那么i自然也不存在,此时dp[i] = dp[i-1],分数不变,因为i没得删。如果i-1没被删去,那么 dp[ i ] = dp[ i-2 ]+num[i]*i;
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+;
ll num[maxn];
ll dp[maxn];
int main()
{
ll n;
cin>>n;
int maxx=-;
int x;
for(int i=;i<=n;i++)
{
cin>>x;
num[x]++;
if(maxx<x)
maxx=x;
}
dp[]=num[]; //初始dp[1]
for(int i= ; i <= maxx; i++ )
{
dp[i]=max(dp[i-],dp[i-]+num[i]*i);
}
cout<<dp[maxx]<<endl;
}
最长递增子序列。
比如对于{5,6,7,4,2,8,3} 那么最长就是{5,6,7,8}长度为4.
HDU 1257 最少拦截系统
中文题意,求最长递增子序列。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 3e4+;
typedef long long ll;
ll a[maxn];
ll dp[maxn];
int main()
{
ll n;
while(cin>>n)
{ for(int i=;i<n;i++)
cin>>a[i];
for(int i = ; i< n;i++)
dp[i]=;
ll maxx=-;
for(int i = ;i<n;i++)
{
for(int j = ; j < i ; j++)
{
if(a[i]>a[j])
{
dp[i]=max(dp[i],dp[j]+); //还是之前的思想,选或者不选
}
}
maxx=max(dp[i],maxx);
}
cout<<maxx<<endl;}
}
求最长递增子序列的和
这个样例很误导人啊,这个题意呢,就是从起点跳到终点,保持递增跳而且得分最大。注意,起点和终点是不计分的;
模板改一下就好了,之前求的是序列长度。这里求和,那么只要把dp初始化a[ ],依然还是探讨每个数选还是不选的问题。转移方程:
if(a[i]>a[j])
dp[ i ]=max(dp[ i ],dp[ j ]+a[ i ])
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1e6+;
typedef long long ll;
ll a[maxn];
ll dp[maxn];
int main()
{
ll n ;
while(cin>>n)
{
if(n==)
break;
for(int i = ; i<n;i++)
cin>>a[i];
for(int i=;i<n;i++)
dp[i]=a[i];
ll maxx=-;
ll sum = ;
for(int i = ;i <n ; i++)
{
for(int j = ; j< i; j++)
{
if(a[i]>a[j])
{
dp[i]=max(dp[i],dp[j]+a[i]);
}
}
maxx=max(dp[i],maxx);
}
cout<<maxx<<endl;
}
}
A
我们称长度为 s 的序列 f 为波浪序列,当且仅当满足f1≤f2>f3≤...或 f1>f2≤f3>...且有 s≥2
给定一个长度为 n 的序列 {a},输出其有多少个子区间满足其为波浪序列
输入描述
第 11 行包含 11 个正整数,表示序列的长度 nn
第 22 行包含 nn 个正整数,分别表示序列中的每一个元素 a_iai
输出描述
输出一行11 个正整数表示答案
5
1 2 3 2 1
输出
5
样例解释 1
区间[1,2] [2,3] [3,2] [2,1] [2,3,2] 满足题意,所以共有 5 个波浪序列。
这个题用DP解比较简单,其他的解法我并没有看懂。所谓波浪,单独一个数字不能算,两个数字一定算上。我们的二维dp,j=0表示下降或相等,j =1 表示上升。i 从0到n
转移方程:
if(a[i-]<=a[i])
{
dp[i][]=dp[i-][]+;
}
else
dp[i][]=dp[i-][]+;
sum+=dp[i][]+dp[i][];
拿样例来解释一下:
我们可以写出这么个东西: 0 1
1 0 1
2 0 1
3 2 0
4 1 0
sum逐个加就是答案。 第一步,从 i =1 开始,出现上升,则dp[1][1]=dp[0][0]+1;
第二步,i=2 , 2->3还是上升,但是dp[2][1]不能承接上一个dp[1][1],因为三个上升数不是波浪,需要承接dp[0][1],再加1(差不多算是重置吧)
第三步, i =3 ,3->2,出现下降,dp[3][0]=dp[2][1]+1=2,这里说明一下,dp[2][1]存的是2->3,+1里的这个1,是新的3->2,原来的2->3接上3->2,数目还是那个数目,既dp[3][0]=dp[2][1]+1=2。
总的来说,这个转移方程中,+1就是加的当前新的波浪,而上一步的dp,是之前的波浪接上了此次的新波浪,数目依然是上一个dp,但是样子已经不同了,所以要用sum进行累加。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll ;
const int maxn = 3e6+;
int dp[maxn][];
int a[maxn];
int main()
{
int n ;
cin>>n;
for(int i = ; i< n ;i ++)
cin>>a[i];
ll sum = ;
for(int i = ; i< n ; i++)
{
if(a[i-]<=a[i])
{
dp[i][]=dp[i-][]+;
}
else
dp[i][]=dp[i-][]+;
sum+=dp[i][]+dp[i][];
} cout<<sum<<endl;
}
区间DP:
给一堆石子,相邻的合并,问最后得到的最小花费,花费具体算法在题里。
对于此题,根据常识,对于最终状态,是由两团合并的。所以定义dp[i][j]表示区间i-j合并的最小值。
二堆合并:dp[1][2]=dp[1][1]+dp[2][2]+sum[1~2];
即dp[i][i+1]=dp[i][i]+dp[i+1][i+1]+sum[i~i+1];
三堆合并:dp[1][3]=min(dp[1][1]+dp[2][3],dp[1][2]+dp[3][3])+sum[1~3];
dp[i][i+2]=min(dp[i][i]+dp[i+1][i+2],dp[i][i+1]+dp[i+2][i+2])+sum[i~i+2];
综上推广到第i堆到第j堆的合并,dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
三个for,相当于遍历每一个长度的区间。
感觉有点floyed 的意思.....找中转点
#include<iostream>
#include<cstdio>
#include<cstring>
const int maxn = ;
const int inf = 1e9;
int dp[maxn][maxn];
int a[maxn],sum[maxn];
using namespace std;
int main()
{
int n;
cin>>n;
sum[]=;
for(int i = ;i <= n ; i++)
{
cin>>a[i];
sum[i]=sum[i-]+a[i];
}
for(int len = ; len <= n ;len++)
{
for(int l = ; l+len-<=n; l++)
{
int r=l+len-;
dp[l][r]=inf;
for(int k = l ; k < r ; k ++)
{
dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+][r]+sum[r]-sum[l-]);
}
}
}
cout<<dp[][n]<<endl;
}
还是区间DP
题意就是,给定字符串s,长度为m,由n个小写字母构成。在s的任意位置增删字母,把它变为回文串,增删特定字母的花费不同。求最小花费。
对于样例1: 3 4
abcb
a 1000 1100
b 350 700 c 200 800
在abcb首端插入bcb花费最小。
dp学习笔记(各种dp,比较杂)的更多相关文章
- 数位DP学习笔记
数位DP学习笔记 什么是数位DP? 数位DP比较经典的题目是在数字Li和Ri之间求有多少个满足X性质的数,显然对于所有的题目都可以这样得到一些暴力的分数 我们称之为朴素算法: for(int i=l_ ...
- DP学习笔记
DP学习笔记 可是记下来有什么用呢?我又不会 笨蛋你以后就会了 完全背包问题 先理解初始的DP方程: void solve() { for(int i=0;i<;i++) for(int j=0 ...
- 树形DP 学习笔记
树形DP学习笔记 ps: 本文内容与蓝书一致 树的重心 概念: 一颗树中的一个节点其最大子树的节点树最小 解法:对与每个节点求他儿子的\(size\) ,上方子树的节点个数为\(n-size_u\) ...
- [总结] 动态DP学习笔记
学习了一下动态DP 问题的来源: 给定一棵 \(n\) 个节点的树,点有点权,有 \(m\) 次修改单点点权的操作,回答每次操作之后的最大带权独立集大小. 首先一个显然的 \(O(nm)\) 的做法就 ...
- 斜率优化DP学习笔记
先摆上学习的文章: orzzz:斜率优化dp学习 Accept:斜率优化DP 感谢dalao们的讲解,还是十分清晰的 斜率优化$DP$的本质是,通过转移的一些性质,避免枚举地得到最优转移 经典题:HD ...
- 树形$dp$学习笔记
今天学习了树形\(dp\),一开始浏览各大\(blog\),发现都\(TM\)是题,连个入门的\(blog\)都没有,体验极差.所以我立志要写一篇可以让初学树形\(dp\)的童鞋快速入门. 树形\(d ...
- 状压dp学习笔记(紫例题集)
P3451旅游景点 Tourist Attractions 这个代码其实不算是正规题解的(因为我蒟蒻)是在我们的hzoj上内存限制324MIB情况下过掉的,而且经过研究感觉不太能用滚动数组,所以那这个 ...
- [学习笔记]区间dp
区间 \(dp\) 1.[HAOI2008]玩具取名 \(f[l][r][W/I/N/G]\) 表示区间 \([l,r]\) 中能否压缩成 \(W/I/N/G\) \(Code\ Below:\) # ...
- [学习笔记]树形dp
最近几天学了一下树形\(dp\) 其实早就学过了 来提高一下打开树形\(dp\)的姿势. 1.没有上司的晚会 我的人生第一道树形\(dp\),其实就是两种情况: \(dp[i][1]\)表示第i个人来 ...
随机推荐
- Vue - 引入本地图片的两种方式
第一种,只引入单个图片,这种引入方法在异步中引入则会报错. 比如需要遍历出很多图片展示时 <image :src = require('图片的路径') /> 第二种,可引入多个图片,也可引 ...
- struts2--通配符映射
1.通配符映射: --规则: > 1)若找到多个匹配,没有通配符的优先: > 2)若指定动作不存在,struts2将会尝试把这个URI与任何一个包含着通配符*的动作名进行匹配: > ...
- 原生JS获取所有标签的数量并统计每个标签的数量
<script type="text/javascript"> var tags = document.getElementsByTagName('*'); var t ...
- 修剪草坪 HYSBZ - 2442
在一年前赢得了小镇的最佳草坪比赛后,FJ变得很懒,再也没有修剪过草坪.现在,新一轮的最佳草坪比赛又开始了,FJ希望能够再次夺冠. 然而,FJ的草坪非常脏乱,因此,FJ只能够让他的奶牛来完成这项工作.F ...
- 卸载重装ngin的问题解决方案
1,卸载nginx不保留配置文件 $ sudo apt-get --purge remove nginx 2,卸载自动安装且不再需要的依赖包 $ sudo apt-get autoremove 3,卸 ...
- Day8 - G - Bound Found ZOJ - 1964
Signals of most probably extra-terrestrial origin have been received and digitalized by The Aeronaut ...
- 洛谷题解P1047 校门外的树
题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,…,L,都种有 ...
- 数据结构——java Queue类
定义 队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作. LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用 图例 Que ...
- ConfigureDefender – Windows Defender 设置工具
用于配置Windows 10内置Defender防病毒设置的实用程序.它是一个便携式实用程序 ConfigureDefender实用程序是一个GUI应用程序,用于在Windows 10上查看和配置重要 ...
- Dive into re Module in Python
Dive into RE in Python Standard re module in python is powerful to handle text manipulation,such as ...