Little C Loves 3 III
题解
挺好的做法,想到了还是挺简单的。
首先这个形式我们是很容易想到卷积的,但由于有
j
∣
k
=
i
j|k=i
j∣k=i与
j
&
k
=
0
j\&k=0
j&k=0两个条件不好直接卷积。
我们可以先考虑到将
j
&
k
=
0
j\&k=0
j&k=0这个条件转化一下,让我们在多项式乘法的过程中可以直接处理掉。
由于最后答案是要
m
o
d
4
mod\,4
mod4的,设
b
i
t
x
bit_{x}
bitx表示
x
x
x中一的个数,将
a
i
a_{i}
ai变为
a
i
⋅
4
b
i
t
i
a_{i}\cdot 4^{bit_{i}}
ai⋅4biti,
b
i
b_{i}
bi变成
b
i
⋅
4
b
i
t
i
b_{i}\cdot 4^{bit_{i}}
bi⋅4biti,再做或卷积乘起来求出
c
i
c_{i}
ci。
那么此时的
c
i
c_{i}
ci也应该是
c
i
⋅
4
b
i
t
i
c_{i}\cdot 4^{bit_{i}}
ci⋅4biti。但由于这是或卷积乘起来的,此处的
c
i
c_{i}
ci包含的不止
4
b
i
t
i
4^{bit_{i}}
4biti。
我们观察一下,哪些不止
4
b
i
t
i
4^{bit_{i}}
4biti。很明显,有
b
i
t
j
∣
k
+
b
i
t
j
&
k
=
b
i
t
j
+
b
i
t
k
bit_{j|k}+bit_{j\&k}=bit_{j}+bit_{k}
bitj∣k+bitj&k=bitj+bitk。只有当
j
&
k
=
0
j\&k=0
j&k=0时,才有
b
i
t
j
∣
k
=
b
i
t
j
+
b
i
t
k
bit_{j|k}=bit_{j}+bit_{k}
bitj∣k=bitj+bitk。
所以,当我们将
c
i
c_{i}
ci除去
4
b
i
t
i
4^{bit_{i}}
4biti后,
j
&
k
=
0
j\&k=0
j&k=0的在
c
i
c_{i}
ci中是实值,其它的都包含
4
4
4的幂。
此时,我们在模一个
4
4
4,就只有
j
&
k
=
0
j\&k=0
j&k=0的会产生贡献了。
所以,我们只需要改改后做一次FWT就可以了。
时间复杂度 O ( n l o g n ) O\left(nlog\,n\right) O(nlogn)
源码
注意数组大小,开 2 22 2^{22} 222会MLE。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define MAXN (1<<21)+5
#define lowbit(x) (x&-x)
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef unsigned int uint;
typedef pair<int,int> pii;
const int INF=0x7f7f7f7f;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int lim,n,bit[MAXN],a[MAXN],b[MAXN];
inline void FWTor(LL *A,const int typ){
for(int k=1;k<=lim;k<<=1)
for(int i=0;i<lim;i+=(k<<1))
for(int j=i;j<i+k;j++)
if(j+k<lim)A[j+k]+=1ll*typ*A[j];
}
LL A[MAXN],B[MAXN];
signed main(){
read(n);lim=(1<<n);for(int i=1;i<lim;i++)bit[i]=bit[i>>1]+(i&1);
for(int i=0;i<lim;i++)scanf("%1d",&a[i]),A[i]=(1ll*a[i])<<bit[i]+bit[i];FWTor(A,1);
for(int i=0;i<lim;i++)scanf("%1d",&b[i]),B[i]=(1ll*b[i])<<bit[i]+bit[i];FWTor(B,1);
for(int i=0;i<lim;i++)A[i]=A[i]*B[i];FWTor(A,-1);
for(int i=0;i<lim;i++)printf("%lld",(A[i]>>bit[i]+bit[i])&3);
return 0;
}
本文详细介绍了如何利用快速傅里叶变换(FFT)解决位运算问题,特别是处理‘按位或’操作时的条件限制。通过转换条件并巧妙地调整数据,使得在模4运算下,仅保留满足特定条件的贡献,从而实现高效计算。最终,通过实例展示了算法的时间复杂度为O(nlogn)的源代码实现。
1686

被折叠的 条评论
为什么被折叠?



