FWT模板题 牛客网暑期ACM多校训练营(第九场)A. Circulant Matrix

**作者:tokitsukaze
链接:https://www.nowcoder.com/discuss/94787?type=101&order=0&pos=1&page=0
来源:牛客网

题解:
观察样例感觉是个卷积,然后发现是个xor的FWT。
题意转换成,给个a数组和c数组,求一个b数组,使得a数组和b数组做FWT后的结果为c数组。
然后观察FWT的过程:对a,b数组做FWT,c[i]=a[i]*b[i],然后对c数组做UFWT。
我们把这个过程倒过来:先对c数组做UFWT,然后对a数组做FWT,然后b[i]=c[i]/a[i],最后对b数组做FWT,就把b数组还原了。**

#include <bits/stdc++.h>
using namespace std;
#define int long long
int read()
{
    int x=0;
    char ch=getchar();
    while (!isdigit(ch))
        ch=getchar();
    while (isdigit(ch))
        x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    return x;
}
const int N=362148,mod=1e9+7;
int rev;
int n,a[N],b[N],c[N],v=0;
//void debug(int  a[],int n)
//{
//    cout<<"数组a为"<<endl;
//   int top = 1;
//   for(int i=0;i<=n;i++)
//   {
//       if(top)top =0;
//       else printf(" ");
//       printf("%d",a[i]);
//   }
//   printf("\n");
//}
int Pow(int x,int y)
{
    int ans=1;
    for (; y; y>>=1,x=1LL*x*x%mod)
        if (y&1)
            ans=1LL*ans*x%mod;
    return ans;
}

void FWT(int a[],int n)
{
    for(int d=1;d<n;d<<=1)
        for(int m=d<<1,i=0;i<n;i+=m)
            for(int j=0;j<d;j++)
            {
                int x=a[i+j],y=a[i+j+d];
                a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
                //xor:a[i+j]=x+y,a[i+j+d]=(x-y+mod)%mod;
                //and:a[i+j]=x+y;
                //or:a[i+j+d]=x+y;
            }
}

void UFWT(int a[],int n)
{
    for(int d=1;d<n;d<<=1)
        for(int m=d<<1,i=0;i<n;i+=m)
            for(int j=0;j<d;j++)
            {
                int x=a[i+j],y=a[i+j+d];
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;
                //rev表示2在模mod下的逆元
                //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
                //and:a[i+j]=x-y;
                //or:a[i+j+d]=y-x;
            }
}
void solve(int a[],int b[],int n)
{
    FWT(a,n);
    FWT(b,n);
    for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%mod;
    UFWT(a,n);
}
signed main()
{

    cin>>n;
   rev = Pow(2,mod-2);
    for(int i=0; i<n; i++)
        scanf("%lld",&a[i]);
    for(int j=0; j<n; j++)
    {
        scanf("%lld",&b[j]);
    }
    FWT(a,n);
    FWT(b,n);
    for(int i=0; i<n; i++)
    {
        a[i] = b[i]*Pow(a[i],mod-2)%mod;
    }
    UFWT(a,n);
    for(int i=0; i<n; i++)
    {
        printf("%lld\n",a[i]);

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/axuhongbo/article/details/81782596