1 条题解

  • 0
    @ 2025-8-24 22:21:05

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Alex_Wei
    **

    搬运于2025-08-24 22:21:05,当前版本为作者最后更新于2020-04-25 15:52:21,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题面传送门

    题意简述:给定一个序列 aa,求出是否有一种排列满足相邻两数之和不是 33 的倍数。

    一些约定:我们设

    • 序列 xxaa 中除三余 00 的数。
    • 序列 yyaa 中除三余 11 的数。
    • 序列 zzaa 中除三余 22 的数。
    • f|f| 表示序列 ff 的大小。

    首先判断无解。

    Case 11y+z+1<x|y|+|z|+1<|x|

    y+z+1|y|+|z|+1 个 “空位” 可以放 33 的倍数,根据抽屉原理,如果 x>y+z+1|x|>|y|+|z|+1,则必然有两个 33 的倍数放在同一个 “空位” 里,即相邻。故无解。

    Case 22y,z>0|y|,|z|>0x=0|x|=0

    如果 y,z>0|y|,|z|>0x=0|x|=0,则必然会有一个除三余 11 的数与除三余 22 的数相邻。故无解。


    接下来考虑构造。构造方法如下:

    首先输出所有除三余 11 的数。输出每个数前,如果 x>1|x|>1,则先输出一个除三余 00 的数 x1x_1,然后将其从 xx 中弹出(xx 的大小会减少,即 xx1|x|\gets|x|-1)。

    • 为什么是 x>1|x|>1?因为除三余 11 的数和除三余 22 的数之间要有一个除三余 00 的数隔开来。

    接着输出所有除三余 22 的数。输出每个数前,如果 x>0|x|>0,则先输出一个除三余 00 的数 x1x_1,然后将其从 xx 中弹出(xx 的大小会减少,即 xx1|x|\gets|x|-1)。

    最后可能还剩下一个除三余 00 的数,输出即可。

    vector <int> b[3];
    
    #define x b[0].size()
    #define y b[1].size()
    #define z b[2].size()
    #define work cout<<b[0].back()<<" ",b[0].pop_back()
    
    int main(){
    	int n=read(),a;
    	for(int i=1;i<=n;i++)a=read(),b[a%3].pb(a);
    	if(y+z+1<x||y&&z&&!x)puts("No"),exit(0);
    	puts("Yes");
    	for(auto i:b[1]){if(x>1)work; cout<<i<<" ";}
    	for(auto i:b[2]){if(x)work; cout<<i<<" ";}
    	if(x)work;
    	return 0;
    }
    
    • 1

    信息

    ID
    5466
    时间
    1000ms
    内存
    32MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者