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\)就不吃,否则就吃。

于是变成了递归问题。

每次要查询最小最大次小,\(\text{set}\)实现,\(\mathcal{O}(n\log{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\n",i);
            }
            // printf("11\n");
            // s[cntT].clear();
            // printf("22\n");
            for(int i = 1; i <= n; i++) 
            {
                // printf("a[%d] : len = %d,soc = %d\n",i,a[i].len,a[i].soc);
                s[cntT].insert(a[i]);
            }
        }
        // printf("Yes\n");
        // 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\n",(*tail).len,(*head).len);
            if(New < (*head2)) 
            {
                // printf("New = %d,head2 = %d\n",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\n",ans);
        if(can()) 
        {
            ans--;
        }
        printf("%d\n",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:\n");
    // 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\n",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\n",i + 1,q[1][i].len);
    }
    printf("\n");
    for(int i = 0; i < siz2; i++) 
    {
        printf("q[2][%d] = %d\n",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\n",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\n",ans);
        if(can()) ans--;
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2020-11-29 11:27  luyiming123  阅读(201)  评论(1编辑  收藏  举报