【题解】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;
}
浙公网安备 33010602011771号