#线性DP#
#1.LIS问题(最长上升子序列)##
F
[
i
]
F[i]
F[i]表示以
A
[
i
]
A[i]
A[i]为结尾的“最长上升子序列”的长度
状态转移方程:
F
[
i
]
=
max
0
<
=
j
<
i
,
a
[
j
]
<
a
[
i
]
(
F
[
j
]
+
1
)
F[i]=\max _{0<=j<i,a[j]<a[i]}(F[j]+1)
F[i]=0<=j<i,a[j]<a[i]max(F[j]+1)
#2.LCS问题(最长公共子序列)##
F
[
i
]
[
j
]
F[i][j]
F[i][j]表示前缀子串
A
[
1
到
i
]
A[1到i]
A[1到i]与
B
[
1
到
j
]
B[1到j]
B[1到j]的“最长公共子序列”的长度
状态转移方程:
F
[
i
]
[
j
]
=
m
a
x
(
F
[
i
−
1
]
[
j
]
或
F
[
i
]
[
j
−
1
]
或
F
[
i
−
1
]
[
j
−
1
]
+
1
(
i
f
A
[
i
]
=
B
[
j
]
)
)
F[i][j]=max(F[i-1][j]或F[i][j-1]或F[i-1][j-1]+1(if A[i]=B[j]))
F[i][j]=max(F[i−1][j]或F[i][j−1]或F[i−1][j−1]+1(ifA[i]=B[j]))
#3.数字三角形##
F
[
i
]
[
j
]
F[i][j]
F[i][j]表示从左上角走到第i行第j列,和最大是多少
状态转移方程:
F
[
i
]
[
j
]
=
A
[
i
]
[
j
]
+
m
a
x
(
F
[
i
−
1
]
[
j
]
或
F
[
i
−
1
]
[
j
−
1
]
(
i
f
j
>
1
)
)
F[i][j]=A[i][j]+max(F[i-1][j]或F[i-1][j-1](if j>1))
F[i][j]=A[i][j]+max(F[i−1][j]或F[i−1][j−1](ifj>1))
###CODE###
#include<bits/stdc++.h>
using namespace std;
int n,a[1010][1010];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void init()
{
n=read();
for (int i=1;i<=n;++i)
for (int j=1;j<=i;++j)
a[i][j]=read();
}
void dp()
{
for (int i=n-1;i>=1;--i)
for (int j=1;j<=i;++j)
a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
printf("%d\n",a[1][1]);
}
int main()
{
init();
dp();
return 0;
}
#4.LCIS问题(最长公共上升子序列)##
F
[
i
]
[
j
]
F[i][j]
F[i][j]表示
A
1
到
A
j
A_1到A_j
A1到Aj与
B
1
到
B
j
B_1到B_j
B1到Bj可以构成的以
B
j
Bj
Bj为结尾的LCIS的长度
对于“决策集合中的元素只增多不减少”的情景,就可以维护一个变量来记录决策集合的当前消息,只需要两重循环即可求解。
###CODE###
for (int i=1;i<=n;++i)
{
int val=0;//val是决策集合S(i,j)中f[i-1][k]的最大值
for (int j=1;j<=m;++j)
{
//原来的k循环+判断+状态转移
if (a[i]==b[j]) f[i][j]=val+1;
else f[i][j]=f[i-1][j];
if (b[j]<a[i]) val=max(val,f[i-1][j]);
//j即将增大为j+1,检查j能否进入新的决策集合
}
}
#5.子序列
7.3CF——D
给你n个操作,维护一个multiset
操作①:+ x,在多重集中插入一个x
操作②:-,在多重集中删除一个最小的数
求n个操作的所有子序列中,多重集中所有数的和
题解
外层循环k枚举第k个操作一定选(a[k]一定在多重集中)
f[i][j]表示前i个操作的所有子序列中使得多重集中恰有j个比a[k]小的数的子序列个数
————————————————————————————————————
删数问题
设f[i][j]表示考虑了前i个位置,第i个位置被删除,一共删除了j个位置的最小代价
枚举上一个删除的位置进行转移
#6.方格取数
7.10pk①1004
给你一个数矩阵,如果将你沿途经过的格子上的数字依次记录下来,那么你会得到一个长度为2n-1的序列Q
计算有多少条路线对应这个Q,假设满足条件的路线数为f(Q),你需要输出Σf(Q2)
题解
首先将问题转化为:两个人只能走相同格子从(1,1)到(n,n),问方案数
f[i][u1][v1]表示已经走了i步,第一个人当前横坐标是u1,第二个人横坐标是u2的方案数
转移的时候枚举第一个人走什么方向,第二个人走什么方向,要求走到的格子数字相同, 直接转移(累加方案数)过去就可以
————————————————————————————————————
7.27杭电③1009
给你一个矩阵,每个格子有a、b两个系数
从(1,1)走到(n,n),求Σa*Σb最大值
题解
这题因为保证数据随机,所以每个格子的有效状态比较少
定义pair类型数组f[i][j][],第三维记录第几个状态,f[i][j][].first记录a总和,f[i][j][].second记录b总和
每次只存100个状态,上面转移过来100个状态,左边转移过来100个状态,每次按照Σa*Σb排序只留100个状态
#7.双向DP
7.10CF——E
给你n个格子,在一些格子中有不同温度的空调
一个空调与一个格子的距离是多少,温差就是多少
求每个格子的温度是多少
题解
对于每个格子,只考虑一侧的空调
L[i]表示只在它左边的空调对它产生的最低温,从左到右转移
R[i]表示只在它右边的空调对它产生的最低温,从右到左转移
每个格子的最终答案为min(L[i],R[i])
#8.字符串DP
8.14牛客七夕I
一个长度为偶数并且WF交替出现的字符串为“恋串”
字符串包含待定字符?可以变为WF中的任意一种
统计s的所有子串中可能为“恋串”的个数
题解
设 dp[i][W/F] 表示第 i 个字符为 W/F,以第 i 个字符结尾的最长的“恋串”的长度
for (int i=1;i<=l;++i)
{
if (s[i]=='W') f[i][0]=f[i-1][1]+1;
if (s[i]=='F') f[i][1]=f[i-1][0]+1;
if (s[i]=='?')
{
f[i][0]=f[i-1][1]+1;
f[i][1]=f[i-1][0]+1;
}
ans+=max(f[i][0],f[i][1])/2;
}
#9
设 dp[i][j] 是考虑前 i 个标志并且已经移除了 j 个标志,且不移除第 i 个标志时,在两个城市之间行驶的最短时间。