2020.8.3【算协集训】线性dp

网页链接:传送门
密码:HPUACM

A - 超级楼梯 (HDU-2041)

有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?
Input
输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。
Output
对于每个测试实例,请输出不同走法的数量

Sample InputSample Output
2
2
3
1
2

分析

这题好像之前做过来着,我还以为我写了题解?但是没有找到(也可能是因为没洗细找⑧)那就在这里解释一波。由于刚开始在第 1 1 1 级,每次只能跨上一级或两级,情况就如图所示:

对于第 10 10 10 级楼梯,它可以由第 9 9 9 级或第 8 8 8 级走到,即 d p [ 10 ] = d p [ 9 ] + d p [ 8 ] dp[10]=dp[9]+dp[8] dp[10]=dp[9]+dp[8] .
对于第 9 9 9 级楼梯,它可以由第 8 8 8 级或第 7 7 7 级走到,即 d p [ 9 ] = d p [ 8 ] + d p [ 7 ] dp[9]=dp[8]+dp[7] dp[9]=dp[8]+dp[7] .
对于第 8 8 8 级楼梯,它可以由第 7 7 7 级或第 6 6 6 级走到,即 d p [ 8 ] = d p [ 7 ] + d p [ 6 ] dp[8]=dp[7]+dp[6] dp[8]=dp[7]+dp[6] .
……
以此类推,直到最后只剩下 ≤ 3 ≤3 3 的级数:
对于第 3 3 3 级楼梯,它可以由第 2 2 2 级或第 1 1 1 级走到,即 d p [ 3 ] = 2 dp[3]=2 dp[3]=2 .
对于第 2 2 2 级楼梯,它只可以由第 1 1 1 级走到,即 d p [ 2 ] = 1 dp[2]=1 dp[2]=1 .
对于第 1 1 1 级楼梯,它是起始点,不需要由谁走到,即 d p [ 1 ] = 0 dp[1]=0 dp[1]=0 .

由此我们可以推断出: d p [ i ] = { 0 , i = 1 1 , i = 2 2 , i = 3 d p [ i − 1 ] + d p [ i − 2 ] , i ≥ 4 dp[i]=\begin{cases}0, i=1 \\ 1, i=2 \\ 2, i=3 \\ dp[i-1] + dp[i-2] , i≥4\end{cases} dp[i]=0i=11i=22i=3dp[i1]+dp[i2]i4 .

代码

#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=110;

int N,M,dp[maxn];

void init()
{
	dp[1]=0,dp[2]=1,dp[3]=2;
	for(int i=4;i<maxn;i++)
	{
		dp[i]=dp[i-1]+dp[i-2];
	}
	return ;
}

int main()
{
	scanf("%d",&N);
	init();
	while(N--)
	{
		scanf("%d",&M);
		printf("%d\n",dp[M]);
	}
	return 0;
}

B - 一只小蜜蜂… (HDU-2044)

有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
其中,蜂房的结构如下所示。

Input
输入数据的第一行是一个整数N,表示测试实例的个数,然后是 N 行数据,每行包含两个整数a和b(0<a<b<50)。
Output
对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。

Sample InputSample Output
2
1 2
3 6
1
3

分析

观察蜂房的布局,我们发现它是有规律的——上一行都是奇数,下一行都是偶数;每行当中两个元素之差与另一行对应的两个元素之差都相等;等等——我们就可以想到,不同起点到不同终点的距离如果相等,就说明它们的路线数都是相等的。
举波栗子:
1→22→33→44→5……的路线数都是 1 1 1 .
1→32→43→54→6……的路线数都是 2 2 2 .
1→42→53→64→7……的路线数都是 3 3 3 .(以1→4为例,路线为 ①1-2-3-4;②1-2-4;③1-3-4)
1→52→63→74→8……的路线数都是 5 5 5 .(以1→5为例,路线为 ①1-2-3-4-5;②1-2-3-5;③1-2-4-5;④1-3-4-5;⑤1-3-5)
……
举出足够多的栗子后(或者找规律比较秀),我们可以找到规律:对于起终点相差的距离 i i i ,路线数为 d p [ i ] = { 1 , i = 1 2 , i = 2 d p [ i − 1 ] + d p [ i − 2 ] , i ≥ 3 dp[i]=\begin{cases}1, i=1 \\ 2, i=2 \\ dp[i-1] + dp[i-2] , i≥3\end{cases} dp[i]=1i=12i=2dp[i1]+dp[i2]i3 .

注意要用long long。(因为斐波那契数增长得非常快)

代码

#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=110;

int N,a,b;
ll dp[maxn];

void init()
{
	dp[1]=1,dp[2]=2;
	for(int i=3;i<maxn;i++)
	{
		dp[i]=dp[i-1]+dp[i-2];
	}
	return ;
}

int main()
{
	scanf("%d",&N);
	init();
	while(N--)
	{
		scanf("%d%d",&a,&b);
		printf("%lld\n",dp[b-a]);
	}
	return 0;
}

C - 母牛的故事 (HDU-2018)

有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?
Input
输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0<n<55),n的含义如题目中描述。
n=0表示输入数据的结束,不做处理。
Output
对于每个测试实例,输出在第n年的时候母牛的数量。
每个输出占一行。

Sample InputSample Output
2
4
5
0
2
4
6

分析

记得这道题之前也写过!然后还在奇怪明明说年初就有新牛,为啥第一年不是两头牛,第二年是三头牛……
所以这道题实际上我是看给的样例来推断情况的,如图:

由此我们可以推断出式子: d p [ i ] = { 1 , i = 1 2 , i = 2 3 , i = 3 4 , i = 4 d p [ i − 1 ] + d p [ i − 3 ] , i ≥ 5 dp[i]=\begin{cases}1, i=1 \\ 2, i=2 \\ 3, i=3 \\ 4, i=4 \\ dp[i-1] + dp[i-3] , i≥5\end{cases} dp[i]=1i=12i=23i=34i=4dp[i1]+dp[i3]i5 .( d p [ i − 1 ] dp[i-1] dp[i1] 是上一年有的牛数, d p [ i − 3 ] dp[i-3] dp[i3] 是今年要新添的新牛数)

代码

#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=110;

int N;
ll dp[maxn];

void init()
{
	dp[1]=1,dp[2]=2,dp[3]=3,dp[4]=4;
	for(int i=5;i<maxn;i++)
	{
		dp[i]=dp[i-1]+dp[i-3];
	}
	return ;
}

int main()
{
	init();
	while(~scanf("%d",&N))
	{
		if(N==0)	break;
		printf("%lld\n",dp[N]);
	}
	return 0;
}

D - Common Subsequence (POJ-1458)

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, …, xm > another sequence Z = < z1, z2, …, zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, …, ik > of indices of X such that for all j = 1,2,…,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
Input
The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.
Output
For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.

Sample InputSample Output
abcfbc abfcab
programming contest
abcd mnp
4
2
0

分析

题意比较好理解,就是给定两个字符串,问你这两个字符串的最大公共子串的长度是多少。
为了解决这个问题,我们需要开二维的 d p dp dp 数组,表示第一个字符串前 i i i 个字符和第二个字符串前 j j j 个字符的最大公共子序列长度,并把初值都赋成 0 0 0 ,如图所示:(以字符串 “ a b c d ” “abcd” abcd “ a b d c ” “abdc” abdc 为例)

这里把字符串都往后挪了一个位置,是因为这样写之后推公式比较方便,可以不考虑越界问题随意 − 1 -1 1 。但是比较字符串元素是否相等的时候,还是需要写成 s t r [ i − 1 ] str[i-1] str[i1] 的形式,以免出现错误。最后,问题就变成了求 d p [ l e n 1 ] [ l e n 2 ] dp[len1][len2] dp[len1][len2] 的值。

探讨状态转移方程的推导(怎么求子问题 d p [ i ] [ j ] dp[i][j] dp[i][j] )如图:

  1. s t r 1 [ i − 1 ] = s t r 2 [ j − 1 ] str1[i-1]=str2[j-1] str1[i1]=str2[j1]
    如果 s t r 1 [ i − 1 ] = s t r 2 [ j − 1 ] str1[i-1]=str2[j-1] str1[i1]=str2[j1] ,那么当前最大公共子序列的长度为 “ s t r 1 [ 0 ] , s t r 1 [ 1 ] , ⋯   , s t r 1 [ i − 2 ] ” “str1[0],str1[1],\cdots,str1[i-2]” str1[0],str1[1],,str1[i2] “ s t r 2 [ 0 ] , s t r 2 [ 1 ] , ⋯   , s t r 2 [ i − 2 ] ” “str2[0],str2[1],\cdots,str2[i-2]” str2[0],str2[1],,str2[i2] 的最长公共子序列的长度 + 1 +1 +1 ,即 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j]=dp[i-1][j-1]+1 dp[i][j]=dp[i1][j1]+1
    以图中给出的栗子为例:
    i = 1 , j = 1 i=1,j=1 i=1,j=1 时,字符串 “ a ” “a” a “ a ” “a” a 比较, “ a ” “a” a “ a ” “a” a 相等, d p [ 1 ] [ 1 ] = d p [ 0 ] [ 0 ] + 1 = 1 dp[1][1]=dp[0][0]+1=1 dp[1][1]=dp[0][0]+1=1 .
    i = 2 , j = 2 i=2,j=2 i=2,j=2 时,字符串 “ a b ” “ab” ab “ a b ” “ab” ab 比较, “ b ” “b” b “ b ” “b” b 相等, d p [ 2 ] [ 2 ] = d p [ 1 ] [ 1 ] + 1 = 2 dp[2][2]=dp[1][1]+1=2 dp[2][2]=dp[1][1]+1=2 .
    i = 3 , j = 4 i=3,j=4 i=3,j=4 时,字符串 “ a b c ” “abc” abc “ a b d c ” “abdc” abdc 比较, “ c ” “c” c “ c ” “c” c 相等, d p [ 3 ] [ 4 ] = d p [ 2 ] [ 3 ] + 1 = 3 dp[3][4]=dp[2][3]+1=3 dp[3][4]=dp[2][3]+1=3 .
    ……
  2. s t r 1 [ i − 1 ] ≠ s t r 2 [ j − 1 ] str1[i-1]≠str2[j-1] str1[i1]=str2[j1]
    s t r 1 [ i − 1 ] ≠ s t r 2 [ j − 1 ] str1[i-1]≠str2[j-1] str1[i1]=str2[j1] ,那么当前最大公共子序列的长度为 m a x ( “ s t r 1 [ 0 ] , s t r 1 [ 1 ] , ⋯   , s t r 1 [ i − 2 ] ” max(“str1[0],str1[1],\cdots,str1[i-2]” max(str1[0],str1[1],,str1[i2] “ s t r 2 [ 0 ] , s t r 2 [ 1 ] , ⋯   , s t r 2 [ i − 1 ] ” , s t r 1 [ 0 ] , s t r 1 [ 1 ] , ⋯   , s t r 1 [ i − 1 ] ” “str2[0],str2[1],\cdots,str2[i-1]” ,str1[0],str1[1],\cdots,str1[i-1]” str2[0],str2[1],,str2[i1],str1[0],str1[1],,str1[i1] “ s t r 2 [ 0 ] , s t r 2 [ 1 ] , ⋯   , s t r 2 [ i − 1 ] ” ) “str2[0],str2[1],\cdots,str2[i-1]”) str2[0],str2[1],,str2[i1])的最长公共子序列的长度,即 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j]=max(dp[i-1][j],dp[i][j-1]) dp[i][j]=max(dp[i1][j],dp[i][j1])
    以图中给出的栗子为例:
    i = 1 , j = 2 i=1,j=2 i=1,j=2 时,字符串 “ a ” “a” a “ a b ” “ab” ab 比较, “ a ” “a” a “ b ” “b” b 不相等, d p [ 1 ] [ 2 ] = m a x ( d p [ 0 ] [ 2 ] , d p [ 1 ] [ 1 ] ) = 1 dp[1][2]=max(dp[0][2],dp[1][1])=1 dp[1][2]=max(dp[0][2],dp[1][1])=1 。此时的最长公共子序列长度是 1 1 1 ,公共子序列是 “ a ” “a” a .
    i = 2 , j = 1 i=2,j=1 i=2,j=1 时,字符串 “ a b ” “ab” ab “ a ” “a” a 比较, “ b ” “b” b “ a ” “a” a 不相等, d p [ 2 ] [ 1 ] = m a x ( d p [ 1 ] [ 1 ] , d p [ 2 ] [ 0 ] ) = 1 dp[2][1]=max(dp[1][1],dp[2][0])=1 dp[2][1]=max(dp[1][1],dp[2][0])=1 。此时的最长公共子序列长度是 1 1 1 ,公共子序列是 “ a ” “a” a .
    i = 3 , j = 3 i=3,j=3 i=3,j=3 时,字符串 “ a b c ” “abc” abc “ a b d ” “abd” abd 比较, “ c ” “c” c “ d ” “d” d 不相等, d p [ 3 ] [ 3 ] = m a x ( d p [ 2 ] [ 3 ] , d p [ 3 ] [ 2 ] ) = 2 dp[3][3]=max(dp[2][3],dp[3][2])=2 dp[3][3]=max(dp[2][3],dp[3][2])=2 。此时的最长公共子序列长度是 2 2 2 ,公共子序列是 “ a b ” “ab” ab .
    ……

代码

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=1010;

int len1,len2,dp[maxn][maxn];
string str1,str2;

int main()
{
	while(cin>>str1>>str2)
	{
		len1=str1.size();
		len2=str2.size();
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=len1;i++) 
		{
			for(int j=1;j<=len2;j++)
			{
				if(str1[i-1]==str2[j-1])
				{
					dp[i][j]=dp[i-1][j-1]+1;
				}
				else
				{
					dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
				}
			}
		}
		printf("%d\n",dp[len1][len2]);
	}
	return 0;
}

E - Longest Ordered Subsequence (POJ-2533)

A numeric sequence of ai is ordered if a1 < a2 < … < aN. Let the subsequence of the given numeric sequence (a1, a2, …, aN) be any sequence (ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).
Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
Output
Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.

Sample InputSample Output
7
1 7 3 5 9 4 8
4

分析

题目写了一长串,实际上是问你给定序列中的最长上升子序列(严格上升)的长度是多少。

先读入原序列数据,存放到 a a a 数组中。然后可以在读入的过程中统计最长上升子序列的长度,也可以读完后再统计,这里是边读边记的做法(因为这样快点)。

d p [ i ] dp[i] dp[i] 表示以第 i i i 个元素作结的最长上升子序列的长度,那么对于每个 i i i ,它的 d p [ i ] dp[i] dp[i] 的初值都是 1 1 1 (一个数本身就是递增序列)。
对于 j < i j<i j<i ,如果 a [ j ] < a [ i ] a[j]<a[i] a[j]<a[i] ,说明 a [ j ] a[j] a[j] a [ i ] a[i] a[i] 是一小段上升子序列。此时应该比较 d p [ i ] dp[i] dp[i] d p [ j ] + 1 dp[j]+1 dp[j]+1 的大小。如果 d p [ i ] > d p [ j ] + 1 dp[i]>dp[j]+1 dp[i]dp[j]+1 ,说明之前存放的以 a [ i ] a[i] a[i] 作为结尾的子序列比现在碰见的更长,因此不做改变;如果 d p [ i ] < d p [ j ] + 1 dp[i]<dp[j]+1 dp[i]<dp[j]+1 ,说明之前存放的以 a [ i ] a[i] a[i] 作为结尾的子序列比现在碰见的更短,因此更新 d p [ i ] dp[i] dp[i] 的值为 d p [ j ] + 1 dp[j]+1 dp[j]+1
最后用 r e s res res 存放序列中最长上升序列的长度,并在循环结束后输出其结果。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=1010;

int N,a[maxn],dp[maxn],res;

int main()
{
	scanf("%d",&N);
	res=1;
	for(int i=1;i<=N;i++)
	{
		scanf("%d",&a[i]);
		dp[i]=1;
		for(int j=1;j<i;j++)
		{
			if(a[j]<a[i])	
			{
				dp[i]=max(dp[i],dp[j]+1);
			}
		}
		res=max(res,dp[i]);
	}
	printf("%d",res);
	return 0;
}

F - Super Jumping! Jumping! Jumping! (HDU-1087)

Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. Maybe you are a good boy, and know little about this game, so I introduce it to you now.
The game can be played by two or more than two players. It consists of a chessboard(棋盘)and some chessmen(棋子), and all chessmen are marked by a positive integer or “start” or “end”. The player starts from start-point and must jumps into end-point finally. In the course of jumping, the player will visit the chessmen in the path, but everyone must jumps from one chessman to another absolutely bigger (you can assume start-point is a minimum and end-point is a maximum.). And all players cannot go backwards. One jumping can go from a chessman to next, also can go across many chessmen, and even you can straightly get to end-point from start-point. Of course you get zero point in this situation. A player is a winner if and only if he can get a bigger score according to his jumping solution. Note that your score comes from the sum of value on the chessmen in you jumping path.
Your task is to output the maximum value according to the given chessmen list.
Input
Input contains multiple test cases. Each test case is described in a line as follow:
N value_1 value_2 …value_N
It is guarantied that N is not more than 1000 and all value_i are in the range of 32-int.
A test case starting with 0 terminates the input and this test case is not to be processed.
Output
For each case, print the maximum according to rules, and one line one case.

Sample InputSample Output
3 1 3 2
4 1 2 3 4
4 3 3 2 1
0
4
10
3

分析

这题和上一题差不多,只不过题意变成了求给定序列中的最大上升子序列和。而 d p [ i ] dp[i] dp[i] 的初值不是 1 1 1 而是每个元素的值 a [ i ] a[i] a[i] ,且发现 a [ j ] < a [ i ] a[j]<a[i] a[j]<a[i] 后, d p [ i ] dp[i] dp[i] 存放的也是 d p [ i ] dp[i] dp[i] d p [ j ] + a [ i ] dp[j]+a[i] dp[j]+a[i] 中的较大值。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=1010;

int N,a[maxn],dp[maxn],res;

int main()
{
	while(~scanf("%d",&N))
	{
		if(N==0)	break;
		res=0;
		memset(a,0,sizeof(a));
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=N;i++)
		{
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=N;i++)
		{
			dp[i]=a[i];	//如果之前的元素都比a[i]大,a[i]就自己形成序列,和为a[i]
			for(int j=1;j<i;j++)
			{
				if(a[j]<a[i])	
				{
					dp[i]=max(dp[i],dp[j]+a[i]);
				}
			}
		}
		for(int i=1;i<=N;i++)
		{
			res=max(res,dp[i]);	//找到子序列中的最大和
		}
		printf("%d\n",res);
	}
	return 0;
}

G - Jumping Cows (POJ-2181)

Farmer John’s cows would like to jump over the moon, just like the cows in their favorite nursery rhyme. Unfortunately, cows can not jump.
The local witch doctor has mixed up P (1 <= P <= 150,000) potions to aid the cows in their quest to jump. These potions must be administered exactly in the order they were created, though some may be skipped.
Each potion has a ‘strength’ (1 <= strength <= 500) that enhances the cows’ jumping ability. Taking a potion during an odd time step increases the cows’ jump; taking a potion during an even time step decreases the jump. Before taking any potions the cows’ jumping ability is, of course, 0.
No potion can be taken twice, and once the cow has begun taking potions, one potion must be taken during each time step, starting at time 1. One or more potions may be skipped in each turn.
Determine which potions to take to get the highest jump.
Input
* Line 1: A single integer, P
* Lines 2…P+1: Each line contains a single integer that is the strength of a potion. Line 2 gives the strength of the first potion; line 3 gives the strength of the second potion; and so on.
Output
* Line 1: A single integer that is the maximum possible jump.

Sample InputSample Output
8
7
2
1
8
4
3
5
6
17

分析

题意:给定 P P P 个数字,从前往后开始取数。一开始初值为 0 0 0 ,奇数次操作加上取的数,偶数次操作减去取的数,问最后最大结果是多少。

这道题有两种做法,一个是贪心,一个是 d p dp dp

  • 贪心
    贪心的思想就是每次都取最优解,那么对于奇数次操作要加数,我们就从后面序列中取上升序列中最大的数加上;对于偶数次操作要减数,我们就从后面序列中取下降序列中最小的数减去。直到最后遍历完整个数组为止。

  • d p dp dp
    j i [ i ] ji[i] ji[i] 表示:当拿到第 i i i 个数时,前面已经拿了奇数个数得到的最大值; o u [ i ] ou[i] ou[i] 表示:当拿到第 i i i 个数时,前面已经拿了偶数个数得到的最大值。

    • i i i 个数在奇数次操作中被选中
      如果第 i i i 个数是在奇数次操作中被选中的,就有两种情况:① j i [ i ] = j i [ i − 1 ] ji[i]=ji[i-1] ji[i]=ji[i1] ——前面 i − 1 i-1 i1 个取奇数个,当前这个不要;② j i [ i ] = o u [ i − 1 ] + a [ i ] ji[i]=ou[i-1]+a[i] ji[i]=ou[i1]+a[i] ——前面 i − 1 i-1 i1 个取偶数个,当前这个要。在这两种情况中取最大的,存放进 j i [ i ] ji[i] ji[i] 中。

    • i i i 个数在偶数次操作中被选中
      如果第 i i i 个数是在偶数次操作中被选中的,就有两种情况:① o u [ i ] = o u [ i − 1 ] ou[i]=ou[i-1] ou[i]=ou[i1] ——前面 i − 1 i-1 i1 个取偶数个,当前这个不要;② o u [ i ] = j i [ i − 1 ] + a [ i ] ou[i]=ji[i-1]+a[i] ou[i]=ji[i1]+a[i] ——前面 i − 1 i-1 i1 个取奇数个,当前这个要。在这两种情况中取最大的,存放进 o u [ i ] ou[i] ou[i] 中。

    最后输出数组 j i ji ji 最后一个元素和数组 o u ou ou 最后一个元素当中最大的那个值就🆗了。

代码

  1. 贪心
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const ll maxn=150010;
    
    int N,a[maxn],dp[maxn],res,cnt;
    
    int main()
    {
    	scanf("%d",&N);
    	for(int i=1;i<=N;i++)
    	{
    		scanf("%d",&a[i]);
    	}
    	res=0,cnt=1;	//res储存结果,cnt记录是奇数次操作还是偶数次操作
    	int i;
    	for(i=1;i<=N;i++)
    	{
    		if(cnt&1)	//奇数次
    		{
    			while(i<=N && a[i]<=a[i+1])	i++;
    			res+=a[i];
    			cnt++;
    		}
    		else	//偶数次
    		{
    			while(i<=N && a[i]>=a[i+1])	i++;
    			res-=a[i];
    			cnt++;
    		}
    	}
    	printf("%d\n",res);
    	return 0;
    }
    
  2. d p dp dp
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const ll maxn=150010;
    
    int N,a[maxn],ji[maxn],ou[maxn];
    
    int main()
    {
    	scanf("%d",&N);
    	ji[0]=ou[0]=0;
    	for(int i=1;i<=N;i++)
    	{
    		scanf("%d",&a[i]);
    		ji[i]=max(ji[i-1],ou[i-1]+a[i]);
    		ou[i]=max(ou[i-1],ji[i-1]-a[i]);
    	}
    	printf("%d\n",max(ji[N],ou[N]));
    	return 0;
    }
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值