Wannafly Winter Camp Day8(Div1, onsite) I题 岸边露伴的人生经验

Wannafly Winter Camp Day8(Div1, onsite)

I题 岸边露伴的人生经验

有点无聊,写点博客打发时间吧。
在这里插入图片描述
在这里插入图片描述
就按照题解所说的,把它转化成一个20位的二进制数。记录这 n n n个数 ( &lt; 2 20 ) (&lt;2^{20}) (<220)的出现次数,对这个数组套个fwt的板子。两个向量距离的平方最大为40,算一下每种距离二元组的数量,然后分别算贡献就行了。注意一下四元组是和顺序有关系的,本题就没有了。

AC_code

#include<bits/stdc++.h>
#define clr(a, b) memset(a,b,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long LL;

const int MXN = 3e5 + 7;
const int MOD = 998244353;
int n, m, Q;
int LN;
LL ar[1<<21], br[MXN], inv2;
LL ksm(LL a, int b) {
    LL res = 1;
    for(; b; b>>=1, a=a*a%MOD) {
        if(b&1) res = res * a % MOD;
    }
    return res;
}
void FWT_xor(LL *a,int LN,int opt) {
    for(int i=1;i<LN;i<<=1)
        for(int p=i<<1,j=0;j<LN;j+=p)
            for(int k=0;k<i;++k) {
                LL 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]=a[j+k]*inv2%MOD,a[i+j+k]=a[i+j+k]*inv2%MOD;
            }
}
int main() {
    inv2 = ksm(2, MOD - 2);
    scanf("%d", &n);
    for(int i = 0, tmp; i < n; ++i) {
        tmp = 0;
        for(int j = 0, x; j < 10; ++j) {
            scanf("%d", &x);
            if(x == 0) tmp <<= 2;
            else if(x == 1) tmp <<= 2, tmp |= 1;
            else tmp <<= 1, tmp |= 1, tmp <<= 1;
        }
        ++ ar[tmp];
    }
    LN = (1<<20);
    FWT_xor(ar, LN, 1);
    for (int i = 0; i < LN; ++i) ar[i] = ar[i] * ar[i] % MOD;
    FWT_xor(ar, LN, -1);
    //ar[x] 表示有多少对ai和aj异或结果为x
    LL ans = 0;
    for(int i = 0, tmp, cnt; i < LN; ++i) {
        tmp = i; cnt = 0;
        for(int j = 0, x; j < 10; ++j) {
            x = tmp & 3;
            if(x == 3) x = 1;
            if(x == 2) x = 4;
            cnt += x;
            tmp >>= 2;
        }
        br[cnt] = (br[cnt] + ar[i]) % MOD;
    }
    for(int i = 0; i <= 40; ++i) {
        ans = (ans + br[i]*br[i]%MOD)%MOD;
    }
    printf("%lld\n", ans);
    return 0;
}

fwt模板

void FWT_or(int *a,int LN,int opt) {
    for(int i=1;i<LN;i<<=1)
        for(int p=i<<1,j=0;j<LN;j+=p)
            for(int k=0;k<i;++k)
                if(opt==1)a[i+j+k]=(a[j+k]+a[i+j+k])%MOD;
                else a[i+j+k]=(a[i+j+k]+MOD-a[j+k])%MOD;
}
void FWT_and(int *a,int LN,int opt) {
    for(int i=1;i<LN;i<<=1)
        for(int p=i<<1,j=0;j<LN;j+=p)
            for(int k=0;k<i;++k)
                if(opt==1)a[j+k]=(a[j+k]+a[i+j+k])%MOD;
                else a[j+k]=(a[j+k]+MOD-a[i+j+k])%MOD;
}
void FWT_xor(int *a,int LN,int opt) {
    for(int i=1;i<LN;i<<=1)
        for(int p=i<<1,j=0;j<LN;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;
            }
}
void FWT_and(ll *P,int LN,int opt) {
    for(int i=2;i<=LN;i<<=1)
        for(int p=i>>1,j=0;j<LN;j+=i)
            for(int k=j;k<j+p;++k)
                P[k]+=P[k+p]*opt;
}
void FWT_or(ll *P,int LN,int opt) {
    for(int i=2;i<=LN;i<<=1)
        for(int p=i>>1,j=0;j<LN;j+=i)
            for(int k=j;k<j+p;++k)
                P[k+p]+=P[k]*opt;
}
void FWT_xor(int *P,int LN,int opt) {
    for(int i=2;i<=LN;i<<=1)
        for(int p=i>>1,j=0;j<LN;j+=i)
            for(int k=j;k<j+p;++k) {
                int x=P[k],y=P[k+p];
                P[k]=(x+y)%MOD;P[k+p]=(x-y+MOD)%MOD;
                if(opt==-1)P[k]=1ll*P[k]*inv2%MOD,P[k+p]=1ll*P[k+p]*inv2%MOD; 
            }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值