1 条题解

  • 0
    @ 2025-8-24 21:37:29

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Created_equal1
    **

    搬运于2025-08-24 21:37:29,当前版本为作者最后更新于2016-01-25 13:21:10,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    设F[i]表示将前i个人处理完毕所要用的最少寝室个数

    考虑暴力的O(n^2)的转移,我们会发现,时间大多数用在了寻找最小且满足条件的情况

    可以考虑分情况讨论,对于都是膜拜一个人的情况用数组记录,对于膜拜人数的绝对值不大于M的情况,化简得到一个不等式,然后用线段树(单点修改,区间最值)记录。

    具体分析看我的代码和代码开头的注释。

    
    //j~i可以放在一间宿舍(j<=i)  c01[i]表示前i个人中膜拜c01的人数,yyy[i]同理
    //情况1:c01[j - 1] = c01[i]
    //情况2:yyy[j - 1] = c01[i]
    //情况3:设a = yyy[i] - yyy[j - 1]   b = c01[i] - c01[j - 1]
    //       |a - b| <= M
    //需满足:①a - b <= M 
    //        =>(yyy[i] - yyy[j - 1]) - (c01[i] - c01[j - 1]) <=M
    //        =>yyy[i] - yyy[j - 1] - c01[i] + c01[j - 1] <= M
    //        =>c01[j - 1] - yyy[j - 1] <= M + c01[i] - yyy[i] 
    //      ②b - a <= M
    //        =>yyy[j - 1] - c01[j - 1] <= M + yyy[i] - c01[i]
    //        =>c01[j - 1] - yyy[j - 1] >= c01[i] - yyy[i] - M
    //整理可得 情况3等价于:
    // c01[i] - yyy[i] - M <= c01[j - 1] - yyy[j - 1] <= M + c01[i] - yyy[i]
    
    //情况1和情况2用数组记录,情况3用线段树处理 时间复杂度O(nlogn) 
    
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const size_t Max_N(500050);
    const int Add(500000);
    const int INF(0X3F3F3F3F);
    
    void Get_Val(int &Ret)
    {
        Ret = 0;
        char ch;
        while ((ch = getchar()), (ch > '9' || ch < '0'))
            ;
        do
        {
            (Ret *= 10) += ch - '0';
        }
        while ((ch = getchar()), (ch >= '0' && ch <= '9'));
    }
    
    struct node
    {
        int l, r;
        int Min;
    };
    
    struct Segment_Tree
    {
        node segt[Max_N << 3];
        void build_tree(const int&, const int&, const int&);
        void change(const int&, const int&, const int &);
        int rmq_min(const int&, const int&, const int&);
        inline
        void pushup(const int &cur)
        {
            segt[cur].Min = min(segt[cur << 1].Min, segt[(cur << 1) | 1].Min);
        }
    };
    Segment_Tree Space;
    
    void Segment_Tree::build_tree(const int &cur, const int &l, const int &r)
    {
        segt[cur].l = l, segt[cur].r = r, segt[cur].Min = INF;
        if (l == r)
            return;
        int mid = l + ((r - l) >> 1);
        build_tree(cur << 1, l, mid);
        build_tree((cur << 1) | 1, mid + 1, r);
    }
    
    void Segment_Tree::change(const int &cur, const int &i, const int &x)
    {
        if (segt[cur].l == i && segt[cur].r == i)
        {
            segt[cur].Min = x;
            return;
        }
        int mid = segt[cur].l + ((segt[cur].r - segt[cur].l) >> 1);
        if (i <= mid)
            change(cur << 1, i, x);
        else
            change((cur << 1) | 1, i, x);
        pushup(cur);
    }
    
    int Segment_Tree::rmq_min(const int &cur, const int &l, const int &r)
    {
        if (segt[cur].l == l && segt[cur].r == r)
            return segt[cur].Min;
        int mid = segt[cur].l + ((segt[cur].r - segt[cur].l) >> 1);
        if (r <= mid)
            return rmq_min(cur << 1, l, r);
        else
            if (l > mid)
                return rmq_min((cur << 1) | 1, l, r);
            else
                return min(rmq_min(cur << 1, l, mid), rmq_min((cur << 1) | 1, mid + 1, r));
    }
    
    int N, M;
    int c01[Max_N], yyy[Max_N];
    
    int F[Max_N];
    int c01_dp[Max_N], yyy_dp[Max_N];
    int Minus[Max_N << 1];
    
    void init()
    {
        int v;
        Get_Val(N), Get_Val(M);
        for (int i = 1;i <= N;++i)
        {
            Get_Val(v);
            yyy[i] = yyy[i - 1] + (v == 1);
            c01[i] = c01[i - 1] + (v == 2);
        }
    }
    
    void dp()
    {
        memset(c01_dp, 0X3F, sizeof(c01_dp));
        memset(yyy_dp, 0X3F, sizeof(yyy_dp));
        memset(Minus, 0X3F, sizeof(Minus));
        Minus[0 + Add] = c01_dp[0] = yyy_dp[0] = F[0] = 0;
        Space.build_tree(1, -500000, 500000);
        Space.change(1, 0, 0);
        int a, b, c;
        for (int i = 1;i <= N;++i)
        {
            a = c01_dp[c01[i]];
            b = yyy_dp[yyy[i]];
            c = Space.rmq_min(1, c01[i] - yyy[i] - M, M + c01[i] - yyy[i]);
            F[i] = min(min(a + 1, b + 1), min(c + 1, F[i - 1] + 1));
            c01_dp[c01[i]] = min(c01_dp[c01[i]], F[i]);
            yyy_dp[yyy[i]] = min(yyy_dp[yyy[i]], F[i]);
            if (F[i] < Minus[c01[i] - yyy[i] + Add])
            {
                Minus[c01[i] - yyy[i] + Add] = F[i];
                Space.change(1, c01[i] - yyy[i], F[i]);
            }
        }
        printf("%d", F[N]);
    }
    
    int main()
    {
        init();
        dp();
        return 0;
    }
    
    
    • 1

    信息

    ID
    1437
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者