【题解】AT_arc222_e [ARC222E] XOR Matching

https://www.luogu.com.cn/problem/AT_arc222_e

\(o_x\) 表示 \(x\)\(A\) 中的出现次数,令 \(V=2^{20}\)

  • \(X=0\):显然只能每个数内部自己匹配。\(f(0)=\sum_{i=0}^{V-1} \left\lfloor\frac{o_i}{2}\right\rfloor\),需要特殊处理。
  • \(X>0\):显然 \(i\) 只能和 \(i\oplus X\) 匹配。那么 \(f(X)=\frac{1}{2}\sum_{i=0}^{V-1} \min(o_i,o_{i\oplus x})\)

那么有 \(\sum_{X>0} f(X)=\sum_{i=0}^{V-1}\sum_{j=0}^{i-1}\min(o_i,o_j)\times 10^{i\oplus j}\)
求这个式子可以先把 \(A\) 数组去重,按照 \(o_i\) 从大到小排序。此时只有 \(i\) 前面的 \(j\) 可以与 \(i\) 产生贡献,而 \(\min(o_i,o_j)=o_i\)

考虑高低位分治维护,\(j\) 对于前 \(10\) 位任意修改的数进行贡献,\(i\) 查询后 \(10\) 位任意修改的数。这样复杂度平衡为 \(O(n\sqrt V)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL N=(1<<20)+10,P=998244353;
LL n,m,a[N],o[N],ans,pw[N],f[N];
bool cmp(int x,int y) { return o[x]>o[y]; }
int main()
{
	scanf("%lld%lld",&n,&m);
	m=1<<m;
	pw[0]=1;
	for(int i=1;i<m;i++) pw[i]=pw[i-1]*10%P;
	for(int i=1;i<=n;i++) scanf("%lld",a+i),o[a[i]]++;
	sort(a+1,a+n+1);
	n=unique(a+1,a+n+1)-a-1;
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		LL x=a[i],sum=0;
		ans=(ans+o[x]/2)%P;
		for(int j=0;j<1024;j++)
			sum=(sum+f[x>>10<<10|j]*pw[(x&1023)^j])%P;
		ans=(ans+o[x]*sum)%P;
		for(int j=0;j<1024;j++)
			(f[(j<<10)|(x&1023)]+=pw[((x>>10)^j)<<10])%=P;
	}
	printf("%lld",ans);
	return 0;
}
posted @ 2026-07-03 09:36  TallBanana  阅读(7)  评论(0)    收藏  举报