• [51Nod1773] A国的贸易


    Description

    给定一个长度为 (2^n ( n le 20)) 的序列,编号从 (0) 开始,每次操作时,对于第 (i) 个数,他会加上所有下标为 (j) 的数(本轮操作之前的版本),其中 (i,j) 的二进制表示中有且仅有一位不同。求 (t le 10^9) 次操作后的序列在 (mod 10^9 + 7) 下的结果。

    Solution

    构造数组 (b[]),其中 (1,2,4,8,...) 位置为 (1),其余均为 (0),则显然每次操作后的序列 (a'[]) 就是原序列 (a[])(b[]) 的异或卷积,于是目标序列 (c[]=a[]*b[]^t)

    用 FWT 将异或卷积转化为算数乘法,用快速幂解决即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    const int N = 1 << 21 | 1;
    const int mod = 1e9+7;
    
    int T;
    
    int qpow(int p,int q)
    {
        return (q&1 ? p : 1) * (q ? qpow(p*p%mod,q/2) : 1) % mod;
    }
    
    int inv(int p)
    {
        return qpow(p, mod-2);
    }
    
    int 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<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    
    void write(int x)
    {
        if(x<0){
        	putchar('-');
    		x=-x;
    	}
        if(x>9)
    		write(x/10);
        putchar(x%10+'0');
    }
    
    void rd(int &x)
    {
        x=read();
    }
    
    void md(int &a)
    {
        a%=mod;
        a+=mod;
        a%=mod;
    }
    
    //////////////////////////
    namespace fwt
    {
    int n, m;
    int a[N], b[N];
    
    void load(int m, int *A, int *B)
    {
        n = 1 << m;
        for (int i = 0; i < n; i++) a[i] = A[i], b[i] = B[i];
    }
    
    void get()
    {
        for(int i=0;i<n;i++) b[i]=qpow(b[i],T);
        for (int i = 0; i < n; i++) a[i] *= b[i], md(a[i]);
    }
    
    void OR(int *f, int x = 1)
    {
        for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
            for (int i = 0; i < n; i += o)
                for (int j = 0; j < k; j++)
                    f[i+j+k] += f[i+j] * x, md(f[i+j+k]);
    }
    
    void AND(int *f, int x = 1)
    {
        for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
            for (int i = 0; i < n; i += o)
                for (int j = 0; j < k; j++)
                    f[i+j] += f[i+j+k] * x, md(f[i+j]);
    }
    
    void XOR(int *f, int x = 1)
    {
        for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
            for (int i = 0; i < n; i += o)
                for (int j = 0; j < k; j++)
                    f[i+j] += f[i+j+k],
                              f[i+j+k] = f[i+j] - f[i+j+k] - f[i+j+k],
                                         md(f[i+j]), md(f[i+j+k]),
                                         f[i+j] *= x, f[i+j+k] *= x,
                                                   md(f[i+j]), md(f[i+j+k]);
    }
    
    void solve_and(int m,int *A,int *B,int *c)
    {
        load(m,A,B), AND(a), AND(b), get(), AND(a, mod - 1);
        memcpy(c,a,(1<<m)*sizeof(int));
    }
    
    void solve_or(int m,int *A,int *B,int *c)
    {
        load(m,A,B), OR(a), OR(b), get(), OR(a, mod - 1);
        memcpy(c,a,(1<<m)*sizeof(int));
    }
    
    void solve_xor(int m,int *A,int *B,int *c)
    {
        load(m,A,B), XOR(a), XOR(b), get(), XOR(a, inv(2));
        memcpy(c,a,(1<<m)*sizeof(int));
    }
    } // namespace fwt
    
    int A[N], B[N], C[N];
    
    signed main()
    {
        int n, m;
        rd(m), n = 1 << m;
        rd(T);
        for (int i = 0; i < n; i++) rd(A[i]);
        for (int i=0;i<m;i++) B[1<<i]=1;
        B[0]=1;
    
        fwt::solve_xor(m,A,B,C);
        for(int i=0; i<n; i++) write(C[i]), putchar(' ');
    
        return 0;
    }
    
    
  • 相关阅读:
    教你用笔记本破解无线路由器password
    EJB究竟是什么,真的那么神奇吗??
    Hibernate的介绍
    编程基本功训练:流程图画法及练习
    一年成为Emacs高手(像神一样使用编辑器)
    MfC 进度条控件
    最小生成树(普利姆算法、克鲁斯卡尔算法)
    创建与删除索引
    hdu 4876 ZCC loves cards(暴力)
    springMVC3学习(二)--ModelAndView对象
  • 原文地址:https://www.cnblogs.com/mollnn/p/13581882.html
Copyright © 2020-2023  润新知