http://acm.hdu.edu.cn/showproblem.php?pid=6057
题目大意:
思路:好题,当然也是难题,我们来慢慢分析。考虑对原式子进行变形,设
p
=
i
x
o
r
j
,
q
=
i
o
r
j
p=i\ xor\ j,q=i\ or\ j
p=i xor j,q=i or j,由位运算关系不难得到
i
a
n
d
j
=
q
−
p
=
q
x
o
r
p
i\ and\ j=q-p=q\ xor\ p
i and j=q−p=q xor p,最后一步转化还有一个隐含条件:
q
a
n
d
p
=
p
q\ and\ p=p
q and p=p(其实就是为了保证
p
p
p是
q
q
q的子集)。那么原式就可以写成:
C
[
k
]
=
∑
p
x
o
r
q
=
k
A
[
p
]
∗
B
[
q
]
,
q
a
n
d
p
=
p
C[k]=\sum_{p\ xor\ q=k}A[p]*B[q]\ ,\ q\ and\ p=p
C[k]=p xor q=k∑A[p]∗B[q] , q and p=p
其实这个转换是不等价的,为什么?我们仔细想一下,满足条件的
(
p
,
q
)
(p,q)
(p,q)所对应的
(
i
,
j
)
(i,j)
(i,j)的对数只有一对吗?其实不然,设
b
i
t
s
(
i
)
=
i
bits(i)=i
bits(i)=i的二进制表示中
1
1
1的个数,
i
[
p
o
s
]
i[pos]
i[pos]表示
i
i
i的二进制表示的第
p
o
s
pos
pos位的值,那么对于任意一对满足条件的
(
i
,
j
)
(i,j)
(i,j)来说,
i
[
p
o
s
]
=
0
&
&
j
[
p
o
s
]
=
1
i[pos]=0\&\&j[pos]=1
i[pos]=0&&j[pos]=1或者
i
[
p
o
s
]
=
1
&
&
j
[
p
o
s
]
=
0
i[pos]=1\&\&j[pos]=0
i[pos]=1&&j[pos]=0,对于
p
、
q
p、q
p、q的值其实没有影响,对于以上条件的成立也没有影响。聪明的同学可能到这就明白了,
(
i
,
j
)
(i,j)
(i,j)和
(
p
,
q
)
(p,q)
(p,q)并不是一一对应的,其实有
2
b
i
t
s
(
p
)
2^{bits(p)}
2bits(p)个
(
i
,
j
)
(i,j)
(i,j)对应着同一个
(
p
,
q
)
(p,q)
(p,q),所以我们上面那个式子应该写成:
C
[
k
]
=
∑
p
x
o
r
q
=
k
A
[
p
]
∗
2
b
i
t
s
(
p
)
∗
B
[
q
]
,
q
a
n
d
p
=
p
C[k]=\sum_{p\ xor\ q=k}A[p]*2^{bits(p)}*B[q]\ ,\ q\ and\ p=p
C[k]=p xor q=k∑A[p]∗2bits(p)∗B[q] , q and p=p
你说上面跟着个
2
b
i
t
s
(
p
)
2^{bits(p)}
2bits(p)多难看啊,我们把它换一下:
A
′
[
p
]
=
A
[
p
]
∗
2
b
i
t
s
(
p
)
A'[p]=A[p]*2^{bits(p)}
A′[p]=A[p]∗2bits(p)
C
[
k
]
=
∑
p
x
o
r
q
=
k
A
′
[
p
]
∗
B
[
q
]
,
q
a
n
d
p
=
p
C[k]=\sum_{p\ xor\ q=k}A'[p]*B[q]\ ,\ q\ and\ p=p
C[k]=p xor q=k∑A′[p]∗B[q] , q and p=p
现在考虑对
q
a
n
d
p
=
p
q\ and\ p=p
q and p=p进行转化,其实它就等价于
q
−
p
=
k
q-p=k
q−p=k,等价于
b
i
t
s
(
q
)
−
b
i
t
s
(
p
)
=
b
i
t
s
(
k
)
bits(q)-bits(p)=bits(k)
bits(q)−bits(p)=bits(k)。那么我们可以把它们当成不同的维度来考虑,这样枚举
b
i
t
s
(
p
)
、
b
i
t
s
(
q
)
bits(p)、bits(q)
bits(p)、bits(q)就可以计算出
b
i
t
s
(
k
)
bits(k)
bits(k),那么上式就只剩下:
C
[
k
]
=
∑
p
x
o
r
q
=
k
A
′
[
p
]
∗
B
[
q
]
C[k]=\sum_{p\ xor\ q=k}A'[p]*B[q]
C[k]=p xor q=k∑A′[p]∗B[q]
F
W
T
FWT
FWT就完事了。
时间复杂度
O
(
m
2
∗
2
m
)
O(m^2*2^{m})
O(m2∗2m),还是可以过的。
#include<bits/stdc++.h>
using namespace std; //FWT
typedef long long ll;
const int maxn=1<<20;
const int MOD=998244353;
int n,limit;
int bits[maxn];
ll a[20][maxn],b[20][maxn],c[20][maxn];
inline void FWT_xor(ll *A,int inv)
{
ll x,y;
ll inv2=MOD+1>>1; //因为MOD是一个质数 所以(MOD+1)/2 就是2模MOD的乘法逆元
for(int mid=1;mid<limit;mid<<=1)
{
for(int i=0;i<limit;i+=mid<<1)
{
for(int j=0;j<mid;j++)
{
x=A[i+j],y=A[mid+i+j];
A[i+j]=(x+y)%MOD;
A[mid+i+j]=(x-y+MOD)%MOD;
if(inv==-1)
{
A[i+j]=A[i+j]*inv2%MOD; // 2模MOD的乘法逆元 如果题目不是在模意义下的 除2即可
A[mid+i+j]=A[mid+i+j]*inv2%MOD;
}
}
}
}
}
int main()
{
scanf("%d",&n);
limit=1<<n;
for(int i=0;i<limit;i++)
bits[i]=__builtin_popcount(i);
for(int i=0;i<limit;i++)
{
scanf("%lld",&a[bits[i]][i]);
a[bits[i]][i]*=1<<bits[i];
a[bits[i]][i]%=MOD;
}
for(int i=0;i<limit;i++)
scanf("%lld",&b[bits[i]][i]);
for(int i=0;i<=n;i++)
FWT_xor(a[i],1),FWT_xor(b[i],1);
for(int p=0;p<=n;p++)
for(int q=p;q<=n;q++)
for(int k=0;k<limit;k++)
c[q-p][k]=(c[q-p][k]+a[p][k]*b[q][k])%MOD;
for(int i=0;i<=n;i++)
FWT_xor(c[i],-1);
ll ans=0,base=1;
for(int i=0;i<limit;i++)
{
ans=(ans+c[bits[i]][i]*base)%MOD;
base*=1526;
if(base>=MOD)
base%=MOD;
}
printf("%lld\n",ans);
return 0;
}