5.1 qbxt 一测 T3

                  反物质
【问题描述】
  物理学家有一种假设,世界上存在反物质,反物质遇到正常的物质会发生湮灭。

  假设现在有 n 个粒子,每个粒子的种类用一个 m 以内的正整数表示。现在
要将这些粒子按一定顺序放入一个封闭空间。封闭空间最初什么都没有。

  每当放进一个粒子时,若封闭空间为空或封闭空间中的粒子和放入的粒子
种类相同,这个粒子将留在封闭空间中;若封闭空间中的粒子和放入的粒子种
类不同,则封闭空间中会有一个粒子和放入的粒子抵消(即湮灭)。

  判断是否存在一种排序方案,使得最后封闭空间中有种类编号为“1”的粒
子存在。若存在,最大化最后种类编号为“1”的粒子个数。若多种方案,要求
字典序最小。

【输入格式】
  第 1 行:n 和 m,用空格隔开。
  第 2 到 m+1 行:第 i+1 行代表第 i 种粒子有多少个。每种粒子至少有 1 个。
保证粒子总数是 n。
【输出格式】
  第 1 行:如果最后封闭空间中可以有编号为“1”的粒子存在,输出 YES,否则输出 NO。
  如果第一行输出了 YES,还需继续输出:
  第 2 行:这一行输出最后“1”的个数。
  第 3…n+2 行:输出在能最后“1”有最大数的排序方案里,字典序最小的方案。
  如果第一行输出了 NO,就不必输出其他内容了
【样例输入】
  5 3
  2
  1
  2
【样例输出】
  YES
  1
  1
  3
  2
  3
  1
【数据规模和约定】
  对于 30%的数据, n<=10
  对于 60%的数据, n<=1000
  对于 100%的数据, 1<=m<=n<=10^6

 

考场解题:
  哎呦呦呦,这题只输出最多剩下多少还好,这按字典序排列可就
难为死人啦,这咋排,管他呢,先判断下‘NO’的情况吧,说不定还
能的点分,如果某种粒子的个数超过了总个数的一半,那么一定不能
有‘1’粒子,与之共存,则输出‘NO’ ,此时还需要注意者最多的是
不是 ‘1’ 粒子, 也就到这思路靠谱点, 后边的瞎想就不在此多说了,
总之就是看啥顺眼打打试试吧。


预计得分:10-20(还不得有个‘NO’送点分)
实际得分:0(没爱了)

正解:
代码理解吧:

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1000500;
int n,m;
int num[N];
int big=0;
int cc[N],xu[N];
int last[N];
bool cmp(int x, int y)
{
    return(num[x]<num[y]);
}
void print()
{
    int i,sum=0;
    for(i=1; i<=m; i++)
        xu[i]=i;
    sort(xu+1,xu+m+1,cmp);
    /* for(i=1;i<=m;i++)
    cc[num[i]]++;
    //cc[x]表示粒子数量为x的有几种
    for(i=1;i<=n;i++)
    cc[i]+=cc[i-1];
    //cc[x]表示粒子数量不超过x的有几种
    for(i=1;i<=m;i++)
    xu[cc[num[i]]--]=i;
    //把各种粒子按照num[i]从小到大排序
    */
    for(i=1; i<=m; i++)
    {
        last[i]=num[i];//last剩下多少个i这种粒子
        sum+=last[i];//还有多少该抵消的粒子没抵消
    }
    int top=m; //xu中下标超过top的,num都大于sum/2
    int tot=0; //现在封闭空间中有多少个粒子,粒子编号小于s
    int s=1;  //现在还剩下的粒子中编号最小的
    while(1)
    {
        while(s<=m && !last[s])
            s++;
        if(s>m)
            break;
        if(!tot)
        {
            tot=last[s];
            last[s]=0;
            for(i=1; i<=tot; i++)
                printf("%d\n",s);
        }
        else
        {
            sum-=2;
            tot--;
            while(top && num[xu[top]]>sum/2)
                top--;
            for(i=m; i>top; i--)
            {
                if(last[xu[i]]>sum/2)
                    break;
            }
            if(i>top)
            {
                printf("%d\n",xu[i]);
                last[xu[i]]--;
            }
            else
            {
                printf("%d\n",s);
                last[s]--;
            }
        }
    }
}
int main()
{
    freopen("anti.in","r",stdin);
    freopen("anti.out","w",stdout);
    int i;
    scanf("%d%d%d",&n,&m,&num[1]);
    for(i=2; i<=m; i++)
    {
        scanf("%d",&num[i]);
        if(num[i]*2>n-num[1])
            big=i; // 找出最大种类的数目
    }
    if(big)
    {
        int remain=num[big]-(n-num[1]-num[big]);
        if(num[1]>remain)
        {
            if(m>2)  //如果两类,先输出1 2 结果都一样,字典序最小先输出 1
            {
                int t=num[1]-remain;
                num[1]=remain;
                printf("YES\n%d\n",t);
                print();
                for(i=1; i<=t; i++)
                    printf("1\n");
            }
            else
            {
                int t=num[1]-remain; //t表示要先输出多少个 1
                printf("YES\n%d\n",t);
                for(i=1; i<=num[1]; i++)
                    printf("1\n");
                for(i=1; i<=num[2]; i++)
                    printf("2\n");  //最后输出几个 1
            }
        }
        else
            printf("NO\n");  //若big占比重大, 可以抵消全部的1,则输出‘NO’;
    }
    else
    {
        int t;
        if((n-num[1])%2==1)
        {
            if(num[1]<=1)
            {
                printf("NO\n");
                return 0;
            }
            t=num[1]-1;
            num[1]=1;
        }
        else
        {
            if(num[1]<1)
            {
                printf("NO\n");
                return 0;
            }
            t=num[1];
            num[1]=0;
        }
        printf("YES\n%d\n",t);
        print();
        for(i=1; i<=t; i++)
            printf("1\n");
    }
    return 0;
}
细节多,心累!

 

posted @ 2018-05-06 22:06  Manjusaka丶梦寒  阅读(202)  评论(0编辑  收藏  举报