• P7078 贪吃蛇(snakes)


    说在前面

    UPDATE:这里的单调性证明似乎假了,建议去【被迫营业6】观看。
    考场上就打了个(n = 3),人傻了。

    简单口胡

    现在有(n)个蛇(a_1,a_2,cdots,a_n),考虑(a_n)(a_1),如果:

    • (a_n - a_1 ge a_2),即(a_n)吃完后不是最小的那个,那就吃
    • (a_n - a_1 < a_2) 如果(a_{n - 1})会吃,那么(a_n)就不吃,否则就吃。

    于是变成了递归问题。

    每次要查询最小最大次小,( ext{set})实现,(mathcal{O}(nlog{n}))

    然而加上O2快的一批(指能过)

    # include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int T;
    int n,k;
    int ans = 0;
    int cntT = 0;
    struct node
    {
        int soc,len;
    }a[N];
    
    bool operator <(const struct node &x,const struct node &y)
    {
        if(x.len ^ y.len) return x.len < y.len;
        else return x.soc < y.soc;
    }
    
    node operator + (const struct node &x,const struct node &y)
    {
        node maxl = (x < y) ? y : x;
        node minl = (x < y) ? x : y;
        node news;
        news.len = maxl.len - minl.len;
        news.soc = maxl.soc;
        return news;
    }
    
    set <node> s[11];
    typedef set<node>::iterator its;
    
    bool can()
    {
        if(s[cntT].size() == 2) 
        {
            return 1;
        }
        its head = s[cntT].begin(),head2 = s[cntT].begin(),tail = s[cntT].end();
        ++head2,--tail;
        node New = (*tail) + (*head);
        if(New < (*head2))
        {
            s[cntT].erase(head);
            s[cntT].erase(tail);
            s[cntT].insert(New);
            return !can();
        }
        else
        {
            return 1;   
        }
    }
    
    
    template <typename T> void read(T &x)
    {
        int w = 1;
        x = 0;
        char ch = getchar();
        while(!isdigit(ch))
        {
            if(ch == '-') w = -1;
            ch = getchar();
        }
        while(isdigit(ch))
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        x *= w;
        return;
    }
    
    int main(void)
    {
        // freopen("P7078.in","r",stdin);
        // freopen("P7078.out","w",stdout);
        read(T);
    
        while(++cntT <= T)
        {
            // read(n);
            // s[cntT].clear();
            if(cntT == 1)
            {
                // nn = n;
                read(n);
                for(int i = 1; i <= n; i++)
                {
                    read(a[i].len);
                    a[i].soc = i;
                    s[cntT].insert(a[i]);
                }
            }
            else
            {
                read(k);
                for(int i = 1; i <= k; i++)
                {
                    int x,y;
                    read(x),read(y);
                    a[x].len = y;
                    // printf("Yes %d
    ",i);
                }
                // printf("11
    ");
                // s[cntT].clear();
                // printf("22
    ");
                for(int i = 1; i <= n; i++) 
                {
                    // printf("a[%d] : len = %d,soc = %d
    ",i,a[i].len,a[i].soc);
                    s[cntT].insert(a[i]);
                }
            }
            // printf("Yes
    ");
            // ans = nn;
            while(1)
            {
                its head = s[cntT].begin(),tail = s[cntT].end(),head2 = head;
                ++head2,--tail;
                node New = (*tail) + (*head);
                // printf("tail = %d,head = %d
    ",(*tail).len,(*head).len);
                if(New < (*head2)) 
                {
                    // printf("New = %d,head2 = %d
    ",New.len,(*head2).len);
                    break;
                }
                else 
                {
                    s[cntT].erase(head),s[cntT].erase(tail),s[cntT].insert(New);
                }
            }
            ans = s[cntT].size();
            // printf("ans = %d
    ",ans);
            if(can()) 
            {
                ans--;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    考虑到每次查询最大最小次小都要(mathcal{O}(log{n}))的复杂度,遂想到蚯蚓这题,维护两个队列,一个是原来的,一个是合并的,分别称为(Q_1,Q_2)

    (Q_1)单调性显然,如何证明(Q_2)单调性?

    也很简单。

    考虑现在(Q_2)里有一个(Max - Min),进来一个(Max' - Min'),显然(Max ge Max',Min le Min'),所以(Max - min ge Max' - Min')

    似乎有点牵强,但是珂以尽情猜...

    我用的deque维护,复杂度高啊,还是要加O2才能过。

    # include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6 + 4;
    
    int n,k;
    
    int T,cntT = 0;
    
    template <typename T> void read(T &x)
    {
        int w = 1;
        x = 0;
        char ch = getchar();
        while(!isdigit(ch))
        {
            if(ch == '-') w = -1;
            ch = getchar();
        }
        while(isdigit(ch))
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        x *= w;
        return;
    }
    
    struct node
    {
        int soc,len;
        node(){}
        node(int s,int l) : soc(s),len(l) {}
    }a[N];
    
    deque <node> q[3];
    
    typedef deque<node>::iterator its;
    
    void print(void);
    
    bool operator <(const struct node &x,const struct node &y)
    {
        if(x.len ^ y.len) return x.len < y.len;
        else return x.soc < y.soc;
    }
    
    node operator + (const struct node &x,const struct node &y)
    {
        node maxl = (x < y) ? y : x;
        node minl = (x < y) ? x : y;
        node news;
        news.len = maxl.len - minl.len;
        news.soc = maxl.soc;
        return news;
    }
    
    bool compare(const struct node &x,const struct node &y)
    {
        if(x.len ^ y.len) return x.len < y.len;
        else return x.soc < y.soc;
    }
    
    void clear(void)
    {
        for(int i = 1; i <= 2; i++) 
        {
            while(!q[i].empty()) q[i].pop_back();
        }
        return;
    }
    
    int Max(void)
    {
        node maxl;
        int IT = 0;
        if(q[1].empty())
        {
            if(!q[2].empty())
            {
                maxl = q[2].front();
                // q[2].pop_front();
                IT = 2;
                return IT;
            }
        }
        if(q[2].empty()) 
        {
            if(!q[1].empty()) 
            {
                maxl = q[1].front();
                // q[1].pop_front();
                IT = 1;
                return IT;
            }
        }
        if(q[1].front() < q[2].front()) 
        {
            maxl = q[2].front();
            // q[2].pop_front();
            IT = 2;
        }
        else
        {
            maxl = q[1].front();
            // q[1].pop_front();
            IT = 1;
        }
        return IT;
    }
    
    int Min(void)
    {
        node minl;
        int IT;
        if(q[1].empty())
        {
            if(!q[2].empty()) 
            {
                minl = q[2].back();
                // q[2].pop_back();
                IT = 2;
                return IT;
            }
        }
        if(q[2].empty()) 
        {
            if(!q[1].empty()) 
            {
                minl = q[1].back();
                // q[1].pop_back();
                IT = 1;
                return IT;
            }
        }
        if(q[1].back() < q[2].back()) 
        {
            minl = q[1].back();
            // q[1].pop_back();
            IT = 1;
        }
        else
        {
            minl = q[2].back();
            // q[2].pop_back();
            IT = 2;
        }
        return IT;
    }
    
    node Min2(void)
    {
        node A[5];
        node tmp1 =node(n,INT_MAX),tmp2 = node(n,INT_MAX),tmp3 = node(n,INT_MAX),tmp4 = node(n,INT_MAX);
        int siz1 = q[1].size(),siz2 = q[2].size();
        if(!q[1].empty())
        {
            tmp1 = q[1][siz1 - 1];
            if(siz1 >= 2) tmp2 = q[1][siz1 - 2];
        }
        if(!q[2].empty()) 
        {
            tmp3 = q[2][siz2 - 1];
            if(siz2 >= 2) tmp4 = q[2][siz2 - 2];
        }
        A[1] = tmp1,A[2] = tmp2,A[3] = tmp3,A[4] = tmp4;
        int NN = 4;
        sort(A + 1,A + NN + 1,compare);
        return A[2];
    }
    
    bool can(void)
    {
        // printf("can:
    ");
        // print();
        if(q[1].size() + q[2].size() == 2) return 1;
        node head = q[Min()].back(),tail = q[Max()].front(),head2 = Min2();
        // printf("can : head = %d,tail = %d,head2 = %d
    ",head.len,tail.len,head2.len);
        node New = head + tail;
        if(New < head2) 
        {
            q[Min()].pop_back();
            q[Max()].pop_front();
            q[2].push_back(New);
            return !can();
        }
        else 
        {
            return 1;
        }
    }
    
    void print(void)
    {
        int siz1 = q[1].size(),siz2 = q[2].size();
        for(int i = 0; i < siz1; i++) 
        {
            printf("q[1][%d] = %d
    ",i + 1,q[1][i].len);
        }
        printf("
    ");
        for(int i = 0; i < siz2; i++) 
        {
            printf("q[2][%d] = %d
    ",i + 1,q[2][i].len);
        }
        return;
    }
    
    int main(void)
    {
        // freopen("P7078.in","r",stdin);
        // freopen("P7078.out","w",stdout);
        read(T);
        while(++cntT <= T)
        {
            clear();
            if(cntT == 1)
            {
                read(n);
                for(int i = 1; i <= n; i++) 
                {
                    scanf("%d",&a[i].len);a[i].soc = i;
                }
                for(int i = n; i >= 1; i--) q[1].push_back(a[i]);
            }
            else
            {
                read(k);
                for(int i = 1; i <= k; i++)
                {
                    int x,y;
                    read(x),read(y);
                    a[x].len = y;
                }
                for(int i = n; i >= 1; i--) q[1].push_back(a[i]);
            }
            while(1)
            {
                // print();
                node head = q[Min()].back(),tail = q[Max()].front(),head2 = Min2();
                // printf("head = %d,tail = %d,head2 = %d
    ",head.len,tail.len,head2.len);
                node New = head + tail;
                if(New < head2) 
                {
                    break;
                }
                else
                {
                    q[Min()].pop_back();
                    q[Max()].pop_front();
                    q[2].push_back(New);
                }
            }
            int ans = q[1].size() + q[2].size();
            // printf("ans = %d
    ",ans);
            if(can()) ans--;
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Attributes(特性)与 Properties(属性)的区别
    MFC Ribbon UI 弹出菜单实现分析
    汇编笔记(三)
    一道“简单”的难题
    汇编笔记(四)
    汇编笔记(二)
    汇编笔记(五)
    在XAML里绑定 ElementName RelativeSource 属性
    WPF combobox 解释RelativeSource
    存储过程事务 用事务点处理回滚实例
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/P7078.html
Copyright © 2020-2023  润新知