CodeForces - 1067A Array Without Local Maximums

题目来源:http://codeforces.com/problemset/problem/1067/A

题意:给你一个序列,序列中的-1可以是[1,200]中的任意数,问该数列有多少种情况满足任意a[i]<=max(a[i-1],a[i+1])。

思路:dp。首先定义状态f[i][j][k]表示前i个数,第i个数是j的方案数,其中k=0表示a[i]==a[i-1],k=1表示a[i]<a[i-1]。k=2表示a[i]>a[i-1]。转移的时候如果a[i]是-1就从1到200枚举,否则只更新f[i][a[i]]。

但这样数组为1e5*200*3=6e7。数组开不下。考虑到f[i]只和f[i-1]有关,这样第一维可以用滚动数组优化掉。

更新f[i]的时候需要分类讨论,其中,a[i]=a[i-1]=-1的情况需要用到前缀和优化。

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>

#define ll long long
#define ull unsigned long long
#define BUG cout<<"*************************\n"
using namespace std;

const ll mod = 998244353;
const int maxn = 4e5 + 10;
const int maxm = 1e6 + 10000;
const double eps = 1e-8;

int n, a[maxn];
ll up_sum[maxn][3], down_sum[maxn][3];
ll f[2][211][3];

int main() {
    /*ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);*/
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    if (a[1] == -1) {
        for (int i = 1; i <= 200; ++i) {
            f[1][i][2] = 1;
        }
    } else {
        f[1][a[1]][2] = 1;
    }
    // 1 a[i]<a[i-1]
    // 2 a[i]>a[i-1]
    for (int i = 2; i <= n; ++i) {
        for (int j = 1; j <= 200; ++j)
            f[i & 1][j][0] = f[i & 1][j][1] = f[i & 1][j][2] = 0;
        if (a[i] == -1) {
            if (a[i - 1] == -1) {
                for (int j = 1; j <= 200; ++j) {
                    (up_sum[j][0] = up_sum[j - 1][0] + f[1 - (i & 1)][j][0]) % mod;
                    (up_sum[j][1] = up_sum[j - 1][1] + f[1 - (i & 1)][j][1]) % mod;
                    (up_sum[j][2] = up_sum[j - 1][2] + f[1 - (i & 1)][j][2]) % mod;
                }
                for (int j = 200; j >= 1; --j) {
                    (down_sum[j][0] = down_sum[j + 1][0] + f[1 - (i & 1)][j][0]) % mod;
                    (down_sum[j][1] = down_sum[j + 1][1] + f[1 - (i & 1)][j][1]) % mod;
                    (down_sum[j][2] = down_sum[j + 1][2] + f[1 - (i & 1)][j][2]) % mod;
                }
                for (int j = 1; j <= 200; ++j) {
                    f[i & 1][j][0] = (f[1 - (i & 1)][j][0] + f[1 - (i & 1)][j][1] + f[1 - (i & 1)][j][2]) % mod;
                    f[i & 1][j][1] = (down_sum[j + 1][0] + down_sum[j + 1][1]) % mod;
                    f[i & 1][j][2] = (up_sum[j - 1][0] + up_sum[j - 1][1] + up_sum[j - 1][2]) % mod;
                }
            } else {
                for (int j = 1; j < a[i - 1]; ++j) {
                    f[i & 1][j][1] = (f[1 - (i & 1)][a[i - 1]][0] + f[1 - (i & 1)][a[i - 1]][1]) % mod;
                }
                f[i & 1][a[i - 1]][0] =
                        (f[1 - (i & 1)][a[i - 1]][0] + f[1 - (i & 1)][a[i - 1]][1] + f[1 - (i & 1)][a[i - 1]][2]) % mod;
                for (int j = a[i - 1] + 1; j <= 200; ++j) {
                    f[i & 1][j][2] = (f[1 - (i & 1)][a[i - 1]][0] + f[1 - (i & 1)][a[i - 1]][1] +
                                      f[1 - (i & 1)][a[i - 1]][2]) % mod;
                }
            }
        } else {
            if (a[i - 1] == -1) {
                for (int j = 1; j < a[i]; ++j) {
                    f[i & 1][a[i]][2] += f[1 - (i & 1)][j][0] + f[1 - (i & 1)][j][1] + f[1 - (i & 1)][j][2];
                    f[i & 1][a[i]][2] %= mod;
                }
                f[i & 1][a[i]][0] = (f[1 - (i & 1)][a[i]][0] + f[1 - (i & 1)][a[i]][1] + f[1 - (i & 1)][a[i]][2]) % mod;
                for (int j = a[i] + 1; j <= 200; ++j) {
                    f[i & 1][a[i]][1] += f[1 - (i & 1)][j][0] + f[1 - (i & 1)][j][1];
                    f[i & 1][a[i]][1] %= mod;
                }
            } else {
                if (a[i] > a[i - 1]) {
                    f[i & 1][a[i]][2] =
                            (f[1 - (i & 1)][a[i - 1]][0] + f[1 - (i & 1)][a[i - 1]][1] + f[1 - (i & 1)][a[i - 1]][2]) %
                            mod;
                } else if (a[i] == a[i - 1]) {
                    f[i & 1][a[i]][0] =
                            (f[1 - (i & 1)][a[i - 1]][0] + f[1 - (i & 1)][a[i - 1]][1] + f[1 - (i & 1)][a[i - 1]][2]) %
                            mod;
                } else {
                    f[i & 1][a[i]][1] = (f[1 - (i & 1)][a[i - 1]][0] + f[1 - (i & 1)][a[i - 1]][1]) % mod;
                }
            }
        }
    }
    ll ans = 0;
    for (int i = 1; i <= 200; ++i) {
        ans += f[n & 1][i][0] + f[n & 1][i][1];
        ans %= mod;
    }
    cout << ans << endl;
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值