2024牛客多校9-D-Luner XOR-FWT、凑式子

link:https://ac.nowcoder.com/acm/contest/81604/D
题意:已知 \(n\) 元布尔函数 \(f:\mathbb{Z}_2^n\to \mathbb{Z}_2\)\(\mathbb{Z}_2^n\) 上的一次多项式形如: \(g(x)=a_0 \oplus (a_1 x_1)\dots \oplus (a_n x_n)\) ,定义两个函数的距离 \(d(f,g)=\sum_{x\in \mathbb{Z}_2^n} (f\oplus g)\) 。(1)对所有 \(2^{n+1}\) 个一次多项式,求其到 \(f\) 距离平方之和(2)求 \(d(f,g)\) 最小值。

\(1\leq n\leq 21\).


\(a_0\) 基本是凑数的。
只看 \(a_1,\dots,a_n\) ,意味着对所有 \(2^n\)\(a\),几乎都要求出 \(d(f,g_a)\) 的值,题解给了一个很好的观察:\(f,g\) 都是到 \(\mathbb{Z}_2\) 的函数,\((f\oplus g)=[f\neq g]=\frac{1}{2}-\frac{1}{2}(-1)^{f+g}\),则$$d(f,g)=2^{n-1}-\frac{1}{2}\sum_x (-1)^{f(x)+g(x)}$$
考察后面的式子,\(a_0=0\) 意味着没有影响,\(a_0=1\) 则是乘 \(-1\),最后再处理,只看\(G(x)=\oplus (a_i x_i)=popcount(a\& x)\bmod 2=a\circ x\),这里 \(a\circ x\) 就是异或卷积做FWT变换的时候用到的,回顾一下:
FWT 可以得到\(FWT[A]_i=\sum_{i\circ j=0} A_j-\sum_{i\circ j=1} A_j\).
在这里,如果\(a\circ x=0\),则会有 \((-1)^f\) 的贡献,否则是 \(-(-1)^f\) 的贡献,刚好可以把 \((-1)^{f(x)}\) 作为 \(A(x)\),对其做一次异或的FWT,得到的序列就恰是后面的 \(\sum\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int main(){
    fastio;
    int n;cin>>n;
    int mx=(1<<n),ans=0,mi=INF;
    vector<long long> f(mx);
    rep(i,0,mx-1){
        int x;cin>>x;
        if(x)f[i]=-1;
        else f[i]=1;
    }
    for(int x=2;x<=mx;x<<=1){
        int k=x>>1;
        for(int i=0;i<mx;i+=x)for(int j=0;j<k;j++){
            long long p=f[i+j],q=f[i+j+k];
            f[i+j]=p+q;f[i+j+k]=p-q;
        }
    }
    rep(i,0,mx-1){
        int x=(1<<(n-1))-(f[i]>>1);
        ans=(ans+(long long)x*x)%MOD;
        mi=min(mi,x);

        x=(1<<(n-1))+(f[i]>>1);
        ans=(ans+(long long)x*x)%MOD;
        mi=min(mi,x);
    }
    cout<<ans<<' '<<mi;
    return 0;
}

真是无比奇妙(这玩意真的不是对着FWT的性质,或者某个和FWT相关的研究出的题吗)

posted @ 2024-08-14 01:12  yoshinow2001  阅读(42)  评论(0编辑  收藏  举报