【计数dp】Array Without Local Maximums 【CF1068D】Array Without Local Maximums(计数DP)

参考博客:【CF1068D】Array Without Local Maximums(计数DP)

【题意】

n<=1e5

dp[i][j][k]表示当前第i个数字为j,第i-1个数字与第i个之间大小关系为k的方案数(a[i-1]<a[i],=,>)

转移时使用前缀和和后缀和加速

【状态转移】:

因为情况已经分成三种情况了,小于,等于,大于。

然后根据题目意思,就是不能出现一种情况,a[i-1] < a[i] > a[i+1]

就是说,当我们转移:"大于"时,前一个状态不能是”小于“。

【小结】:

道理我都懂,但我就是写不出来。一头雾水,但是我看了看题解,我就醍醐灌顶了。。。


【代码】(里面有详细的解释)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int mod = 998244353;
 5 const int N = 1e5+5;
 6 const int M = 205;
 7 ll f[N][M][3],tmp;
 8 int a[N],n;
 9 
10 /*
11 f[i][j][k]
12 第i个位置上,的数值为j,与前一个数的关系为k.
13 
14 k = 0  a[i-1] < a[i]        /
15 k = 1  a[i-1] == a[i]       -
16 k = 2  a[i-1] > a[i]        \
17 
18 */
19 
20 
21 int main()
22 {
23     scanf("%d",&n);
24     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
25 
26     /*
27         由于题意让我们a[1] <= a[2]
28         我们初始化时,在1的位置上
29         必须让f[1][i][0],以防止 a[1] > a[2]的情况
30     */
31 
32     for(int i=1;i<=200;i++){
33         if( a[1] == -1 || i == a[1] ) f[1][i][0] = 1 ;
34         else f[1][i][0] = 0 ;
35     }
36     //[2,n]上进行状态转移
37     for(int i=2;i<=n;i++){
38 
39         //枚举当前位置的值,‘=‘的情况 , k = 1 '-'
40         for(int j=1;j<=200;j++){
41             if( a[i] == -1 || a[i] == j )
42                 f[i][j][1] = (f[i-1][j][0]+f[i-1][j][1]+f[i-1][j][2])%mod;
43             else
44                 f[i][j][1] = 0;
45         }
46 
47         //枚举当前位置的值,‘<‘的情况 , k = 0 '/'
48         //∵a[i-1] < a[i]
49         //前一个位置可能有多种情况,所以当前位置应该是记录前缀和
50         tmp = 0 ;
51         for(int j=1;j<=200;j++){
52             if( a[i] == -1 || a[i] == j )
53                 f[i][j][0] = tmp ;
54             else f[i][j][0] = 0 ;
55             tmp = (tmp + f[i-1][j][0] + f[i-1][j][1] + f[i-1][j][2] ) % mod ;
56         }
57 
58         //枚举当前位置的值,‘>‘的情况,  k = 2 '\'
59         //∵a[i-1] > a[i]
60         //前一个位置可能有多种情况,所以当前位置应该是记录后缀和
61         tmp = 0 ;
62         for(int j=200;j>=1;j--){
63             if( a[i] == -1 || a[i] == j )
64                 f[i][j][2] = tmp ;
65             else f[i][j][2] = 0;
66             tmp = ( tmp + f[i-1][j][1] + f[i-1][j][2] ) %mod ;
67         }
68     }
69     ll ans = 0 ;
70 
71     /*
72         题目要求:
73         ∵a[n-1] >= a[n]
74         ∴从两种状态进行转移,k=1.
75     */
76     for(int i=1;i<=200;i++){
77         ans = ( ans + f[n][i][1] + f[n][i][2] ) % mod ;
78     }
79 
80     printf("%lld\n",ans);
81     return 0 ;
82 }
计数dp

猜你喜欢

转载自www.cnblogs.com/Osea/p/11319570.html