P9187 [USACO23OPEN] Field Day S

· · 题解

这里提供一个不同的思路。

首先把每个字符串压缩成一个数。数的范围显然是 [0,2^C),记第 i 个字符串对应的数为 a_i。

对于第 i 个询问,答案等于 \max\limits_{j\in[1,N]}\operatorname{popcount}(a_i\oplus a_j)

如果暴力做,时间复杂度是 O(N^2) 的,不能通过。

换一个思路,从大到小枚举答案 x,判断是否可行。若存在 y\in[0,2^C),j\in[1,N],使得 \operatorname{popcount}(y)=x,且 y\oplus a_j=a_i,就是可行的。

观察关键条件:y\oplus a_j=a_i,这让我们联想到 \text{FWT}。

将 a 中的各个元素丢进桶 t 里面,对于所有 j\in[0,2^C),按照二进制 1 的个数归类,也按照类丢进桶里。然后对于每个类与 t 进行 \text{FWT}。在判断时,只需要判断下标 a_i 的数是否大于 0 即可。

时间复杂度为 O(C^2\cdot2^C)

代码如下: ```cpp #include<bits/stdc++.h> using namespace std; typedef long long ll; const int C=18,N=1e5+1; int c,n; char s[C]; ll a[N],t[1<<C],b[C+1][1<<C],cnt[1<<C]; void fwt_xor(ll a[],int fl) { int n=1<<c; for(int i=2;i<=n;i<<=1){ for(int j=0;j<n;j+=i){ for(int k=j;k<j+i/2;k++){ ll x=a[k]+a[k+i/2],y=a[k]-a[k+i/2]; a[k]=x>>(fl==-1),a[k+i/2]=y>>(fl==-1); } } } } int main() { scanf("%d%d",&c,&n); for(int i=0;i<(1<<c);i++) cnt[i]=cnt[i>>1]+(i&1),b[cnt[i]][i]=1; for(int i=1;i<=n;i++){ scanf("%s",s); for(int j=0;j<c;j++) a[i]=(a[i]<<1)|(s[j]=='G'); t[a[i]]++; } fwt_xor(t,1); for(int i=0;i<=c;i++){ fwt_xor(b[i],1); for(int j=0;j<(1<<c);j++) b[i][j]=b[i][j]*t[j]; fwt_xor(b[i],-1); } for(int i=1;i<=n;i++){ for(int j=c;j>=0;j--){ if(b[j][a[i]]){ printf("%d\n",j); break; } } } } ```