• BZOJ 5267 特工 (类FWT)


    题意

    题解

    从大到小枚举(l), 把一个序列从(2^{l+1})分成两个独立的(2^l),去除两半的影响。
    设去除前的序列为(b), 去除后序列为(b')
    则有(b_{2^{l+1}-1}-b_{2^l-1}=sum^{2^{l+1}-1}_{i=2^l}b_i)
    考虑左边的一个位置(d)与右边的位置(d+2^l)相对应
    考虑一个序列(s_0)的第(i)位为( ext{bitcount}((i ext{or} d) ext{xor} i))(s_1)为把(s_1)(d)换成(d+2^l)的结果
    显然两个序列左半部分完全一样,右半部分完全相反
    (z)(b')(s_0)(或(s_1))左半部分对应位置乘积之和,(y_0,y_1)分别为(b')(s_0,s_1)右半部分对应位置乘积之和
    (b'_d=z,b'_{d+2^l}=y_1)
    且有方程(z+y_0=b_d,z+y_1=b_{d+2^l},y_0+y_1=b_{2^{l+1}-1}-b_{2^l-1})
    解之即可。

    时间复杂度(O(nlog n)).

    代码

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<cassert>
    #define llong long long
    using namespace std;
     
    char c[40000010];
    int ns;
    inline llong read(){
        while(c[ns]<'0'||c[ns]>'9')ns++;
        llong x=0;
        while(c[ns]>='0'&&c[ns]<='9')x=(x<<3)+(x<<1)+c[ns++]-'0';
        return x;
    }
     
    const int N = 1<<20;
    llong a[N+3];
    int n;
     
    int main()
    {
        c[fread(c,1,40000010,stdin)]=0; //input optimization
        n = read();
        for(int i=0; i<n; i++) a[i] = read();
        for(int i=(n>>1); i; i>>=1)
        {
            for(int j=0; j<n; j+=(i<<1))
            {
                llong tmp = a[j+(i<<1)-1]-a[j+i-1];
                for(int k=0; k<i; k++)
                {
                    llong x = a[j+k],y = a[j+i+k];
                    a[j+k] = (-tmp+x+y)>>1,a[j+i+k] = (tmp-x+y)>>1;
                }
            }
        }
        for(int i=0; i<n; i++) printf("%lld ",a[i]); puts("");
        return 0;
    }
    
  • 相关阅读:
    jQuery选择器
    jquery处理json笔记
    观察者模式
    shiro自定义realm
    AysncTask更新progressbar
    android自定义控件
    任务的挂起和激活
    main方法添加2个集合存储图形
    矩形类-内部类刷新
    圆类-内部类多线程刷新
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11616099.html
Copyright © 2020-2023  润新知