专栏文章
P13497 【MX-X14-T7】墓碑密码
P13497题解参与者 3已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @miop06ek
- 此快照首次捕获于
- 2025/12/02 22:47 3 个月前
- 此快照最后确认于
- 2025/12/02 22:47 3 个月前
有点不太像题了,感觉非常诡异,写之前真没觉得能过。
显然如果可以求出 表示 中选出 个数异或和在 的方案数,那么就容易快速回答一次询问,就是 。
问题在于如何快速求出 。考虑 FWT,设集合幂级数 ,其中 这一元表示已选的数的个数,那么就是要求 。根据 FWT 那一套的理论,,。
于是容易写出更加直接的答案:
计算上式也很简单,先对于每个 求出 。又因为 这一项本质上只有 种值,形如 ,于是只需要求出对于每一种 的系数和即可,最后使用二项式定理暴力展开即可得到 。容易做到 。
由于 ,考虑用两个 64 位二进制数(拼成一个 128 位二进制数)去存当 固定时, 的奇偶性,然后从小到大递推转移,转移容易做到线性,每次从删除最低位的状态转移即可。
但是这样子空间爆炸了,实际上也容易解决,枚举 的前 位是啥,那么就只需要开一个 的数组了。
最后回答询问有一些细节需要处理,如果每次暴力 算组合数,那么就是 。一种解决方法是直接预处理 以内的阶乘,由于本题不卡空间,所以开的下。另外一种就是注意到 的变化量是 的,所以每次暴力移动区间乘积也行,但是还是要算一个数的逆元,所以会带 log,好像过不去。
时间复杂度 。
给个部分代码,正常写就能直接过,常数很小。
CPPint n,m,q,a[205],b[205],g[205],dp[205];
ull f1[(1<<20)+5],f2[(1<<20)+5],f3[(1<<20)+5],f4[(1<<20)+5],sta1[25],sta2[25],sta3[25],sta4[25];
int sf[50000205];
inline void solveit(int v){
f1[0]=f2[0]=f3[0]=f4[0]=0;
for(int i=0;i<min(64,n);i++)
if(__builtin_popcountll(v&a[i])&1)f1[0]|=(1ull<<i);
for(int i=64;i<n;i++)
if(__builtin_popcountll(v&a[i])&1)f2[0]|=(1ull<<(i-64));
for(int i=0;i<min(64,m);i++)
if(__builtin_popcountll(v&b[i])&1)f3[0]|=(1ull<<i);
for(int i=64;i<m;i++)
if(__builtin_popcountll(v&b[i])&1)f4[0]|=(1ull<<(i-64));
for(int i=0;i<(1<<20);i++){
if(i){
int p=i^(i&-i),x=__builtin_ctz(i);
f1[i]=(f1[p]^sta1[x]);
f2[i]=(f2[p]^sta2[x]);
f3[i]=(f3[p]^sta3[x]);
f4[i]=(f4[p]^sta4[x]);
}
int c=__builtin_popcountll(f1[i])+__builtin_popcountll(f2[i]);
int c2=__builtin_popcountll(f3[i])+__builtin_popcountll(f4[i]);
int v=dec(m,2*c2);
g[c]=add(g[c],v);
}
}
inline void solve(){
gi(n),gi(m);
for(int i=0;i<n;i++)gi(a[i]);
for(int i=0;i<m;i++)gi(b[i]);
for(int i=0;i<20;i++){
for(int j=0;j<min(64,n);j++)if((1<<(i+8))&a[j])sta1[i]|=(1ull<<j);
for(int j=64;j<n;j++)if((1<<(i+8))&a[j])sta2[i]|=(1ull<<(j-64));
}
for(int i=0;i<20;i++){
for(int j=0;j<min(64,m);j++)if((1<<(i+8))&b[j])sta3[i]|=(1ull<<j);
for(int j=64;j<m;j++)if((1<<(i+8))&b[j])sta4[i]|=(1ull<<(j-64));
}
for(int w=0;w<(1<<8);w++)solveit(w);
int xs=qkpow((1<<28),mod-2);
for(int i=0;i<=n;i++){
for(int j=0;j<=i;j++){
for(int k=0;k<=n-i;k++){
int v=1ll*binom(i,j)*binom(n-i,k)%mod*g[i]%mod;
if(j&1)dp[j+k]=dec(dp[j+k],v);
else dp[j+k]=add(dp[j+k],v);
}
}
}
gi(q);
while(q--){
int N;
gi(N);
int res=0;
for(int i=0;i<=n;i++){
if(N>=i){
int lim=(N-i)/2;
int pro=1ll*fac[lim+n]*inv[lim]%mod;
res=add(res,1ll*pro*inv[n]%mod*dp[i]%mod);
}
}
pi(1ll*res*xs%mod);
}
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...