HDU 6057 Kanade's convolution

来源:互联网 发布:VB 十六进制转rgb 编辑:程序博客网 时间:2024/06/07 06:48

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  yx=k

对于给定 x , y, 有多少满足xy的有序对 (i,j)

因为 ,i and j=k  , x=i xor j , y=i or j

所以 x and k=0x or k=y

这也就是说。xk对立

x是由xor得来。

x中对元素要么属于i要么属于j,不同时成立

x中元素数量为 bit(x), 那么满足,x,y关系的有序对数量为:

i=0(bit(x)i)=2bit(x)

所以:

Ck=xy[x and y=x][yx=k]2bit(x)AxBy

因为 x,k对立。所以:x xor y=k

Ck=x xor y=k[yx=k]2bit(x)AxBy

因为k=x xor y时。

当且仅当bit(y)bit(x)=bit(k)时,xk对立。

所以:

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 600000using 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;}
原创粉丝点击