Comet OJ - 模拟赛 #2 Day1 A波浪 (DP)
地址:https://cometoj.com/contest/76/problem/A?problem_id=4237
解析:这个题用DP解比较简单,其他的解法我并没有看懂。所谓波浪,单独一个数字不能算,两个数字一定算上。我们的二维dp,j=0表示下降或相等,j =1 表示上升。i 从0到n
转移方程:
if(a[i-1]<=a[i]) { dp[i][0]=dp[i-1][1]+1; } else dp[i][1]=dp[i-1][0]+1; sum+=dp[i][0]+dp[i][1];
拿样例来解释一下:
我们可以写出这么个东西: 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+10; int dp[maxn][2]; int a[maxn]; int main() { int n ; cin>>n; for(int i = 0 ; i< n ;i ++) cin>>a[i]; ll sum = 0 ; for(int i = 1 ; i< n ; i++) { if(a[i-1]<=a[i]) { dp[i][0]=dp[i-1][1]+1; } else dp[i][1]=dp[i-1][0]+1; sum+=dp[i][0]+dp[i][1]; } cout<<sum<<endl; }