zoukankan      html  css  js  c++  java
  • 【题解】洛谷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
    ", dp[n]);
        return 0;
    }
  • 相关阅读:
    图片 滚动切换效果(五) 高级篇
    图片 滚动切换效果(四)
    图片 滚动切换效果(三)
    图片 滚动切换效果(二)
    图片 滚动切换效果(一)
    新年第一篇 之 (摄像机可视区域)
    SuperSocket源码解析之开篇 (转)
    矮人国之战 之 阵型 模仿(二)
    Web Service
    XML于JSON
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8546965.html
Copyright © 2011-2022 走看看