• 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
    ",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
    ",xu[i]);
                    last[xu[i]]--;
                }
                else
                {
                    printf("%d
    ",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
    %d
    ",t);
                    print();
                    for(i=1; i<=t; i++)
                        printf("1
    ");
                }
                else
                {
                    int t=num[1]-remain; //t表示要先输出多少个 1
                    printf("YES
    %d
    ",t);
                    for(i=1; i<=num[1]; i++)
                        printf("1
    ");
                    for(i=1; i<=num[2]; i++)
                        printf("2
    ");  //最后输出几个 1
                }
            }
            else
                printf("NO
    ");  //若big占比重大, 可以抵消全部的1,则输出‘NO’;
        }
        else
        {
            int t;
            if((n-num[1])%2==1)
            {
                if(num[1]<=1)
                {
                    printf("NO
    ");
                    return 0;
                }
                t=num[1]-1;
                num[1]=1;
            }
            else
            {
                if(num[1]<1)
                {
                    printf("NO
    ");
                    return 0;
                }
                t=num[1];
                num[1]=0;
            }
            printf("YES
    %d
    ",t);
            print();
            for(i=1; i<=t; i++)
                printf("1
    ");
        }
        return 0;
    }
    细节多,心累!
  • 相关阅读:
    【软件测试】软件缺陷粗浅认识及白盒测试举例
    【软件测试】等价类划分
    【软件测试】对本门课程粗浅理解
    阿里云服务器本地ping超时,远程可以正常ping通
    不忘初心
    开源框架、控件、组件、插件记录
    Flex中窗口可随意拖拽功能实现
    初探数据类型相关问题
    [TSCTF-J 2021] 解题报告
    指针
  • 原文地址:https://www.cnblogs.com/rmy020718/p/8999974.html
Copyright © 2020-2023  润新知