线性DP汇总

#线性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[1i] B [ 1 到 j ] B[1到j] B[1j]的“最长公共子序列”的长度
状态转移方程:
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[i1][j]F[i][j1]F[i1][j1]+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[i1][j]F[i1][j1](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 A1Aj B 1 到 B j B_1到B_j B1Bj可以构成的以 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 个标志时,在两个城市之间行驶的最短时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值