CF1868B1 Candy Party (Easy Version)

· · 题解

思路

首先想要均分糖果,那么必须满足糖果总数 sum 是人数 n 的倍数。

然后我们再取平均值,令 s=\frac{sum} n

因为每个人必须收到一次糖果且只能送出一次糖果,所以对于每一个 a_i,我们首先需要满足 a_i-s 可以被表示为 2^x-2^y

k=|a_i-s|

以二进制的方式来看,\operatorname{lowbit}(k) 应该就是其中一个二次幂,是给出的还是收到的糖果数要看 a_is 的大小关系,那么 k+\operatorname{lowbit}(k) 就应该是另外一个二次幂。

所以,如果 k+\operatorname{lowbit}(k) 不是二次幂,就可以肯定无解。

那么我们再统计每个人需要接受和送出的糖果数的个数,如果接受和送出的糖果数的个数也不相等,那么就无解,否则,有解。

其实还有个特殊情况,那就是原本就有的糖与平均数相同,但是思考一下就会发现不影响结果。

我们只需要把原本就有的糖与平均数相同的人放在给糖过程中间,过一下手就好,比如 a 要给 b 一颗糖,而 k 刚好拥有的糖就是平均数,那么只需要让 ak 一颗糖,然后再由 kb 一颗糖就好,可以发现这样增加一个转手的过程不影响答案,并且也满足了 k 的需求,所以原本就有的糖与平均数一样不需要考虑,可以直接忽略

AC code

#include<bits/stdc++.h>
using namespace std;
inline long long lowbit(long long x){return x&(-x);}
long long T,n,a[200005],sum,flag,k,low;
map<long long,long long>m1,m2;
inline bool sol()
{
    scanf("%lld",&n),m1.clear(),m2.clear(),flag=sum=0;//多测记得清空
    for(long long i=1;i<=n;++i) scanf("%lld",&a[i]),sum+=a[i];
    if(sum%n) return 1;
    sum/=n;
    for(long long i=1;i<=n;++i)
    {
        a[i]-=sum;k=abs(a[i]);low=lowbit(k);k+=low;
        if(k!=lowbit(k)) return 1;//直接使用lowbit判断是不是二次幂
        else if(a[i]>0) ++m1[k],++m2[low];
        else if(a[i]<0) ++m1[low],++m2[k];
    }
    for(auto i=m1.begin(),j=m2.begin();i!=m1.end()&&j!=m2.end();++i,++j) if(flag||i->first!=j->first||i->second!=j->second) return 1;//接受和送出的糖果数的个数是否一样
    return 0;
}
int main()
{
    scanf("%lld",&T);
    while(T--)
        if(sol()) printf("NO\n");
        else printf("YES\n");
    return 0;
}