P9575 「TAOI-2」喵了个喵 Ⅳ

思路

考试的时候打死没想出来,一直在想暴力和质因数分解,我实在是太弱了,比赛后看了官方题解才恍然大悟,于是来写篇题解。

首先是一些特殊点:

  1. n 是偶数时,显然 x 可以取 1,这样 gcd 就都是 1,然后随便平分就好了。恭喜你,你获得了 2 分。

  2. n 不是偶数,且 ai 均为奇数,那么无论怎么 gcd 都是奇数,所以 gcd 之和也一定是奇数,那必然无法划分,那么就是无解。恭喜你,你又获得了 8 分(蒟蒻的我比赛的时候连这都没想到,痛失 8 分)。

  3. n 不是偶数时,这种情况比较难办,下面专门详细讲解。

首先容易发现 x=1 时,gcd 之和就是 n,但是 n 为奇数,显然不满足要求。

这样,我们可以尝试增大 x 的倍数。

假设扩大了 xk 倍,那么 gcd(ai,x) 的变化一定是扩大 l 倍,其中 lk 的因子,那么对于和的贡献是 (l1)×gcd(ai,x)

这样的话,只有 l 为偶数,gcd(ai,x) 为奇数时,贡献才能增加奇数,才能使和变为偶数。

所以我们扩大倍数扩大奇数倍是毫无作用的,扩大倍数含奇数因子意义也不大,所以我们要扩大的倍数只有 2s,sZ 最有效。

那么 s 取几最合适呢?

有两种方法,第一种是挨个试,试到 2s 比最大的 ai 还要大为止,不过没有试过,不清楚会不会 TLE。

第二种,我们可以随意构造一个同时含奇数、偶数的数列,如果奇数的个数奇数个,那就意味着 x 不能取 1,如果把 x 扩大 2 倍,奇数的个数不会变,其余的 gcd 要么不变,要么也扩大 2 倍,和仍然是偶数,所以这种情况一定是无解。那么,我们可以尝试把问题归纳到这种情况解决。

那么,怎么找到那个数呢,这里推荐一种比较方便的方法,那就是 lowbit

lowbit(x) 可以取出 x 在二进制形式下的最末位的 1 以及后面的 0。举个例子,12 的二进制形式是 1100,那么 lowbit(12)=4。(4 的二进制形式是 100

那么,怎么计算 lowbit 呢?

其实很简单,只需要一行代码就能搞定:inline int lowbit(int x){return x&(-x);}

原理就要涉及负数的编码了,负数都是正数的反码再加 1 得到的。

例如 12 的反码就是 0011(省略了前面若干位 1),再加 1 就是 0100,再与原数进行按位与计算,就得到了 lowbit

总而言之就是,二进制末尾有连续多少个 0,反码就有连续多少个 1,再加上一个 1 使其进位,最后与原数一样的就只有最后一个 1 及其后面的 0

所以我们只需要把每个数都除以最小的 lowbit 就可以得到上述的情况。

我们再统计奇数数量,如果数量为偶,则有解;否则,无解。

那么,我们再确定 x=2(除后的,输出记得乘回去),问题就被转化为了有偶数个 1,和奇数个 2 如何分配了。

只需要把两个 1 放在第一组,其他 1 平分,2 平分,然后把多出的一个 2 给第二组就好了。

AC 代码

#include<bits/stdc++.h>
using namespace std;
inline int lowbit(int x){return x&(-x);}
int n,a[100005],low=1000005,sum,flag,cnt1,cnt2=1;
int main()
{
scanf("%d",&n);
if(n%2==0)//先把n为偶的判断了
{
printf("1\n");
for(int i=1;i<=n/2;++i) printf("01");
exit(0);
}
for(int i=1;i<=n;++i) scanf("%d",&a[i]),low=min(low,lowbit(a[i]));//记录最小lowbit
for(int i=1;i<=n;++i) a[i]/=low,sum+=a[i]%2;
if(sum%2) printf("-1"),exit(0);
printf("%d\n",2*low);//记得乘回去
for(int i=1;i<=n;++i)
{
if(a[i]%2)
{
if(flag<2) flag++,a[i]=0;//flag记录在第一组单独放了多少个了
else a[i]=cnt1,cnt1^=1;//然后就是平均分配了
}
else
{
a[i]=cnt2,cnt2^=1;//从第二组开始平均分配
}
}
for(int i=1;i<=n;++i) printf("%d",a[i]);
}
posted @   One_JuRuo  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示