CF1868B1 Candy Party (Easy Version)

发布时间 2023-09-11 15:03:07作者: One_JuRuo

思路

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

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

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

\(k=|a_i-s|\)

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

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

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

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

我们只需要把原本就有的糖与平均数相同的人放在给糖过程中间,过一下手就好,比如 \(a\) 要给 \(b\) 一颗糖,而 \(k\) 刚好拥有的糖就是平均数,那么只需要让 \(a\)\(k\) 一颗糖,然后再由 \(k\)\(b\) 一颗糖就好,可以发现这样增加一个转手的过程不影响答案,并且也满足了 \(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;
}