码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】洛谷P2418 yyy loves OI IV

时间:2018-03-11 23:59:37      阅读:286      评论:0      收藏:0      [点我收藏+]

标签:efi   log   bsp   blog   最小   etc   inf   amp   线段树   

感觉很是妙啊……这题数次误入歧途...最开始想的二维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

标签:efi   log   bsp   blog   最小   etc   inf   amp   线段树   

原文地址:https://www.cnblogs.com/twilight-sx/p/8546965.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!