【JZOJ B组】扑克游戏

题目

FA♂Q

思路

首先,很容易得到,它一定是一棵完全二叉树。
所以,非叶子节点延伸出去的点一定是成对的(废话)

把每张扑克看做一个子树,现在我们要把它们合并。
由于是完全二叉树,且需要分数最小,所以每次合并两棵最小的子树。

是不是有点熟悉?
没错,这就是合并果子!

建一个堆即可解决。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f,maxn=1e4+777;
int c[maxn*2],n,ass=0,cnt=0;
void up(int x)
{
    int i=x;
    while(i/2>0)
    {
        if(c[i]<c[i/2]) swap(c[i],c[i/2]);else break;
        i>>=1;
    }
}
void down(int x)
{
    int i=x;
    while(i*2<=cnt)
    {
        int t=i*2;
        if(t+1<=cnt&&c[t]>c[t+1]) t++;
        if(c[i]>c[t]) swap(c[i],c[t]);else break;
        i=t;
    }
}
void ins(int x)
{
    c[++cnt]=x;
    up(cnt);
}
void del()
{
    swap(c[1],c[cnt]);
    cnt--;
    down(1);
}
int pop()
{
    int x=c[1]; del();
    return x;
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++) 
    {
        int x;
        scanf("%d",&x);
        ins(x);
    }
    while(cnt>1)
    {
        int x1=pop(),x2=pop();
        ass+=x1+x2;
        ins(x1+x2);
    }
    printf("%d",ass);
}

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/80946169