Codeforces 436D Pudding Monsters

题意简述

开始有无限长的一段格子,有n个格子种有布丁怪兽,一开始连续的布丁怪兽算一个布丁怪兽。
每回合你可以将一个布丁怪兽向左或右移动,他会在碰到第一个布丁怪兽时停下,并与其合并。
有m个特殊格子,询问最终你最多可以让几个特殊的格子上被布丁覆盖。

题解思路

dp
f[i]表示前i个布丁最多可覆盖的特殊格子数
g[i]表示前i个布丁,第i个不动的情况下最多可覆盖的特殊格子数
可得转移方程:

g[i] = max(g[i], f[l[i - len] - 1] + sum(b[j], a[i]));
f[r[i + len]] = max(f[r[i + len]], g[i] + sum(a[i] + 1, b[j]));

其中
l[i],r[i]表示第i个布丁所属的怪兽的最左边格子编号和最右边格子编号
len 是枚举特殊格子位置与i的距离
sum(a, b) 表示a,b之间的特殊格子数

代码

#include <cstdio>
#include <algorithm>
const int Maxn = 100010;
int n, m, ll, len;
int a[Maxn], b[Maxn], s[Maxn << 1], l[Maxn], r[Maxn];
int f[Maxn], g[Maxn];
inline void mmax(int& x, const int& y) { if (y > x) x = y; }
inline int sum(const int& x, const int& y) {return s[y] - s[x - 1]; }
int main()
{
    scanf("%d%d", &n, &m);
    for (register int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (register int i = 1; i <= m; ++i)
    {
        scanf("%d", &b[i]);
        ++s[b[i]];
    }
    std::sort(a + 1, a + n + 1);
    std::sort(b + 1, b + m + 1);
    a[0] = -300000; a[n + 1] = 300000;
    for (register int i = 1; i <= n; ++i)
        if (a[i] == a[i - 1] + 1) l[i] = l[i - 1];
        else l[i] = i;
    for (register int i = n; i; --i)
        if (a[i] == a[i + 1] - 1) r[i] = r[i + 1];
        else r[i] = i;
    for (register int i = 1; i <= 200000; ++i) s[i] += s[i - 1];
    for (register int i = 1; i <= n; ++i)
    {
        mmax(f[i], f[i - 1] + sum(a[i], a[i]));
        mmax(g[i], f[i - 1] + sum(a[i], a[i]));
        for (register int j = 1; j <= m && (len = a[i] - b[j]) > 0; ++j)
            if (len < i)
                mmax(g[i], f[l[i - len] - 1] + sum(b[j], a[i]));
        mmax(f[i], g[i]);
        for (register int j = m; j && (len = b[j] - a[i]) >= 0; --j)
            if (len <= n - i)
                mmax(f[r[i + len]], g[i] + sum(a[i] + 1, b[j]));
    }
    printf("%d
", f[n]);
}
原文地址:https://www.cnblogs.com/xuyixuan/p/11191092.html