51Nod 1773 - A国的贸易 - (FWT)

2 篇文章 0 订阅

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1773

本题解用来记录题型,题解来自(侵删):https://blog.csdn.net/zzkksunboy/article/details/79147935

题意

2^n个点,每次i点会使count(i\ xor\ j)=1j点增加a_i个货物,其中count(i)表示i在二进制下1的个数,a_i表示i点上一次的货物数量。

问时刻t之后,每个点货物的数量。

解析

令时刻t的状态为f_t,那么根据题意得出: 

                                                             f_{t,i}=f_{t-1,i}+\sum_{i\ xor\ j=2^k}f_{t-1,j}

怎么看都疑似异或卷积啊,转化一下: 
                                                            f_{t,i}=f_{t-1,i}+\sum_{j\ xor\ 2^k=i}f_{t-1,j}

这明显就是异或卷积的形式了,构造向量A满足: 
                                                                A_0=1,A_i=[\exists2^k=i]

那么f_{t}=f_{t-1}\oplus A,快速幂一下就行了。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2330010;
const int MOD = 1e9 + 7;
const int inv2 = 5e8 + 4;  //2的逆元
int n,N,t,a[MAXN],b[MAXN];
void FWT_xor(int *a,int opt)
{
    for(int i=1;i<N;i<<=1)
        for(int p=i<<1,j=0;j<N;j+=p)
            for(int k=0;k<i;++k)
            {
                int X=a[j+k],Y=a[i+j+k];
                a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;
                if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;
            }
}
int inline read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int pow_mod(int n,int k)
{
    int res=1;
    n=n%MOD;
    while(k>0)
    {
        if(k&1)
            res=(long long)res*n%MOD;
        n=(long long)n*n%MOD;
        k>>=1;
    }
    return res;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
int main()
{
    n=read(), t=read();

    N = 1 << n;
    for (int i = 0; i < N; i++)
    {
        a[i]=read();
    }

    b[0] = 1;
    for (int i = 0; i < n; i++)
    {
        b[1 << i] = 1;
    }

    FWT_xor(a, 1);
    FWT_xor(b, 1);

    for (int i = 0; i < N; i++)
    {
        a[i] = (long long)a[i] * pow_mod(b[i], t) % MOD;
    }

    FWT_xor(a, -1);

    for (int i = 0; i < N; i++)
    {
        write((a[i] + MOD) % MOD);
        putchar(' ');
    }
    putchar(10);
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值