HDU 6057 Kanade’s convolution
原题连接:
http://acm.hdu.edu.cn/showproblem.php?pid=6057
对于这一题
计算:
Ck=∑i and j=kAi xor jBi or j
令:
and 可以理解为交集, or 可以理解为并集, xor 可以理解为交集在并集中的补集。
这里的集合是指,
2
进制形式,每一位取或者不取的情况。
1为取,0为不取。
下面为们把所有整数看作二进制集合。逻辑运算分别对应相应对,集合运算。
xor 并-交
or 并
and 交
令 x=i xor j , y=i or j
由上文并交补的关系有下面等价关系:
i and j=k <−>x and y=x 且 y−x=k
对于给定
x
, y , 有多少满足
x
与y 的有序对
(i,j)
呢
因为 , i and j=k , x=i xor j , y=i or j
所以 x and k=0 , x or k=y
这也就是说。
x
与k 对立
x
是由xor 得来。
x
中对元素要么属于i 要么属于
j
,不同时成立
记x 中元素数量为
bit(x)
, 那么满足,
x,y
关系的有序对数量为:
∑i=0(bit(x)i)=2bit(x)
所以:
Ck=∑x∑y[x and y=x][y−x=k]2bit(x)AxBy
因为
x
,k 对立。所以:
x xor y=k
Ck=∑x xor y=k[y−x=k]2bit(x)AxBy
因为 k=x xor y 时。
当且仅当 bit(y)−bit(x)=bit(k) 时, x,k 对立。
所以:
Ck=∑x xor y=k[bit(y)−bit(x)=bit(k)]2bit(x)AxBy
定义一种数列运算 F() 有:
F(A,k)是一种新数列
并且有:
F(A,k)i=[bit(i)=k]∗Ai
上面的操作其实是吧 一个数列拆成了若干序列。
按照下标二进制 1 的数量拆分。
通过 FWT 得到类似 FFT 的点值表达
既然是点值表达,那么 加 减 乘 就很随意了。
然后通过 FWT(F(A,k)),FWT(F(B,k)) 得到 FWT(F(C,k))
(通过点值表达 进行 乘法,加法)
则:
Ck=F(C,bit(k))k
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAXN 600000
using namespace std;
typedef long long LL;
const LL mod =998244353;
LL Pow(LL a,LL b)
{
LL tmp=1;
a%=mod;
while(b)
{
if(b&1)
tmp=tmp*a%mod;
a=a*a%mod;
b>>=1;
}
return tmp;
}
const LL I2=Pow(2,mod-2);
void FWT(LL y[],int l,int r)
{
if(l==r)return;
int mid=1+((l+r)>>1);
FWT(y,l,mid-1);
FWT(y,mid,r);
for(int i=l,j=mid;i<mid;i++,j++)
{
LL u=y[i];
LL t=y[j];
y[i]=u+t; if(y[i]>=mod)y[i]-=mod;
y[j]=u-t; if(y[j]<0) y[j]+=mod;
}
}
void IFWT(LL y[],int l,int r)
{
if(l==r)return ;
int mid=1+((l+r)>>1);
for(int i=l,j=mid;i<mid;i++,j++)
{
LL u=y[i];
LL t=y[j];
y[i]=(u+t)*I2%mod;
y[j]=(u-t+mod)*I2%mod;
}
IFWT(y,l,mid-1);
IFWT(y,mid,r);
}
LL bit[MAXN];
LL A[23][MAXN];
LL B[23][MAXN];
LL C[23][MAXN];
LL ds[25];
int main ()
{
LL a;
int m;
scanf("%d",&m);
int len=1<<(m++);
for(int i=0;i<len;i++) bit[i]=bit[i>>1]+(i&1);
for(int i=0;i<len;i++)
{
scanf("%lld",&a);
A[bit[i]][i]=(a*(1<<bit[i]))%mod;
}
for(int i=0;i<len;i++) scanf("%lld",B[bit[i]]+i);
for(int i=0;i<m;i++) FWT(A[i],0,len-1);
for(int i=0;i<m;i++) FWT(B[i],0,len-1);
for(int i=0;i<m;i++)
for(int j=i;j<m;j++)
for(int t=0;t<len;t++)
C[j-i][t]=(C[j-i][t]+A[i][t]*B[j][t])%mod;
for(int i=0;i<m;i++) IFWT(C[i],0,len-1);
LL ans=0,base=1;
for(int i=0;i<len;i++)
{
ans=(ans+C[bit[i]][i]*base)%mod;
base=base*1526%mod;
}
printf("%lld\n",ans);
return 0;
}