题解洛谷P2418 yyy loves OI IV

Posted Twilight_Sx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解洛谷P2418 yyy loves OI IV相关的知识,希望对你有一定的参考价值。

感觉很是妙啊……这题数次误入歧途...最开始想的二维dp,单调队列优化;无果,卒。于是没忍住看了下标签:暴力枚举?搜索?于是开始想记忆化搜索。以为会有什么很强的剪枝之类的;30分,卒。最后终于回到正道上:50 0000的数据,只可能有O(n) & O(nlogn)两种复杂度吧?在这样的思想+标签线段树的指引下,总算是走向了光明。

暴力,正解的开端。首先考虑最开始的二维dp,转移方程为:dp[i] = min(dp[k] + 1) (k ∈ 1 ~ i - 1) , 且 i ~ k + 1为合法区间。大部分的时间消耗都在于枚举找最值+判断是否合法上。对于这部分的优化,我们先考虑一段合法的区间:要么相差 <= m, 要么都是一个人的粉丝。第二种情况明显特判就行,可以做到O(n), 暂时撇去不谈。再看第一种情况并列出式子:1. abs (a[i] - a[j - 1] - b[i] + b[j - 1]) <= m; 2. a[i] - b[i] - m <= a[j - 1] - b[j - 1] <= a[i] - b[i] + m. 到这里发现,可以用线段树维护区间的最值,将线段树建成 a[i] - b[i]的权值线段树,每次查询在满足条件的范围内的dp最小值就好了。注意要防止爆负数,加上一个大一点的数。

 

#include <bits/stdc++.h>
using namespace std;
#define INF 1061109567
#define maxn 600000
#define ADD 10000
int n, m, a[maxn], c[maxn], cont = INF, b[maxn], dp[maxn], ans = INF;
int N = 1000000;

struct tree
{
    int l, r, num; 
}T[maxn * 4];

int read()
{
    int x = 0;
    char c;
    c = getchar();
    while(c < 0 || c > 9) c = getchar();
    while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar();
    return x;
}

void Build(int p, int l, int r)
{
    T[p].l = l, T[p].r = r, T[p].num = INF;
    if(l == r) return;
    int mid = (l + r) >> 1;
    Build(p << 1, l, mid), Build(p << 1 | 1, mid + 1, r);
}

void Getmin(int &x, int y)
{
    if(x > y) x = y; 
}

void update(int p, int x, int num)
{
    if(T[p].l == T[p].r) 
    {
        Getmin(T[p].num, num);
        return;
    }
    int mid = (T[p].l + T[p].r) >> 1;
    if(x <= mid) update(p << 1, x, num);
    else update(p << 1 | 1, x, num);
    T[p].num = min(T[p << 1].num, T[p << 1 | 1].num);
}

int query(int p, int l, int r)
{
    int L = T[p].l, R = T[p].r;
    if(R < l || L > r) return INF;
    if(l <= L && r >= R) return T[p].num;
    return min(query(p << 1, l, r), query(p << 1 | 1, l, r));
}

int main()
{
    n = read(), m = read();
    memset(dp, 0x3f3f3f, sizeof(dp));
    Build(1, 1, N);
    for(int i = 1; i <= n; i ++)
    {
        c[i] = read();
        a[i] = a[i - 1] + (c[i] == 1); 
        b[i] = b[i - 1] + (c[i] == 2);
    }
    dp[0] = 0;
    update(1, ADD, dp[0]);
    for(int i = 1; i <= n; i ++)
    {
        bool flag = false;
        if(c[i] == c[i - 1]) dp[i] = cont + 1;
        else flag = true;
        Getmin(dp[i], dp[i - 1] + 1);
        int tem = query(1, a[i] - b[i] - m + ADD, a[i] - b[i] + m + ADD);
        Getmin(dp[i], tem + 1);
        if(flag) cont = min(dp[i - 1], dp[i]);
        else Getmin(cont, dp[i]);
        update(1, a[i] - b[i] + ADD, dp[i]);
    }
    printf("%d\n", dp[n]);
    return 0;
}

 

以上是关于题解洛谷P2418 yyy loves OI IV的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2397 yyy loves Maths VI (mode) 题解

洛谷——P2393 yyy loves Maths II

洛谷 P2393 yyy loves Maths II

[洛谷P1580]yyy loves Easter_Egg I

$题解 P2394 yyy loves Chemistry I$

题解Luogu P2397 yyy loves Maths VI (mode)