CF811C 火车旅行

1 CF811C 火车旅行

2 题目描述

时间限制 \(2s\) | 空间限制 \(256M\)

\(Vladik\) 经常坐火车旅行,他对于一些旅程记忆深刻。\(Vladik\) 在起始的火车站,包括他自己在内一共有 \(n\) 个旅客想上火车。他们已经按照一定的顺序排成一列,他们每个人的目标城市的代码 \(a_i\) 已知。列车长从原始顺序中选择了一些不相交区间(这些区间不能覆盖整个序列)的数字。在同一个区间的旅客被分在同一个车厢里面。在区间选择的时候如果至少有一个旅客的目标城市是 \(x\),那么所有的想去城市 \(x\) 的旅客都会被分在同一个车厢里面,也就是说他们只能在同一个区间内。注意所有去城市 \(x\) 的旅客要么一起去同一个车厢里面,要么就哪里都不去。从位置 \(l\)\(r\) 的旅客的幸福指数等于 \(l\)\(r\) 之间的旅客不同的目标城市代码异或而成。这列火车旅行的幸福指数由每一段幸福指数的累加和构成。帮助 \(Vladik\) 计算最大可能的幸福指数。

数据范围:\(1 ≤ n ≤ 5000\)

3 题解

由于这道题数据范围较小,可以允许我们进行 \(O(n^2)\) 级别的操作。我们就可以考虑枚举 \(l, r\),计算出区间 \([l, r]\) 的异或和 \(sum_{l, r}\)。但是题目中还规定所有目标城市相同的乘客都在同一车厢内。我们可以预处理出对于某目标城市,最左和最右的乘客。如果某区间中去某个城市的乘客没有全部包括,那么我们将该区间的异或和定义为 \(-INF\)

此时我们考虑使用 \(dp\) 计算最大的区间和。设 \(dp_i\) 表示考虑前 \(i\) 个乘客时最大的舒适度,则有 $dp_i = \max(\max_{j = 1}^{i} \limits dp_{j-1} + sum_{j, i}, dp_{i-1}) $。

4 代码(空格警告):

#include <iostream>
#include <cstring>
using namespace std;
const int N = 5e3+10;
int n;
int a[N], sum[N][N], dp[N], xxor[N][N];
int maxn[N], minn[N], maxx, minnn;
bool f[N], f2[N];
int main()
{
    memset(maxn, -0x3f, sizeof(maxn));
    memset(minn, 0x3f, sizeof(minn));
    memset(sum, -0x3f, sizeof(sum));
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++)
    {
        maxn[a[i]] = max(maxn[a[i]], i);
        minn[a[i]] = min(minn[a[i]], i);
    }
    for (int i = 1; i <= n; i++)
    {
        memset(f2, 0, sizeof(f2));
        xxor[i][i] = a[i];
        f2[a[i]] = 1;
        for (int j = i+1; j <= n; j++)
        {
            if (!f2[a[j]])
            {
                xxor[i][j] = xxor[i][j-1] ^ a[j];
                f2[a[j]] = 1;
            }
            else xxor[i][j] = xxor[i][j-1];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        minnn = 0x3f3f3f3f;
        maxx = -0x3f3f3f3f;
        if (minn[a[i]] < i) continue;
        if (maxn[a[i]] == i)
        {
            sum[i][i] = xxor[i][i];
        }
        minnn = min(minnn, minn[a[i]]);
        maxx = max(maxx, maxn[a[i]]);
        for (int j = i+1; j <= n; j++)
        {
            minnn = min(minnn, minn[a[j]]);
            maxx = max(maxx, maxn[a[j]]);
            if (i > minnn || j < maxx) continue;
            sum[i][j] = xxor[i][j];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        dp[i] = dp[i-1];
        for (int j = 1; j <= i; j++)
        {
            dp[i] = max(dp[i], dp[j-1] + sum[j][i]);
        }
    }
    cout << dp[n];
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-28 00:06  David24  阅读(73)  评论(0编辑  收藏  举报