CF449D Jzzhu and Numbers

CF449D Jzzhu and Numbers

黄金定律:给定序列求答案,但答案与序列顺序无关的题目,要么考虑把序列转权值序列,要么对序列排序。

二进制题按大小排序看起来就没啥用,那就转成权值序列。即,设 c(i)c(i) 表示 iiaa 中的出现次数。同时设 VVaa 的值域。

然后直接算发现不是很好算。考虑容斥计算。

g(x)g(x)aa 中为 xx 超集的元素个数,即 g(x)=ixc(i)g(x) = \sum_{i \supseteq x} c(i)。sosdp 板子解决。

f(x)f(x)aa 中,满足这个条件的子序列个数:该子序列中所有数 & 起来的值为 xx 的超集。

我们发现,这样的子序列中,里面每个数必须都是 xx 的超集,否则 & 起来之后 xx 中的 1 位势必会有丢失,无法是 xx 的超集。

换句话说,这个子序列必须从 g(x)g(x) 个数里选。

然后考虑怎么选。发现只要保证每个数都是 xx 的超集,那么 & 起来之后 xx 中的 1 位肯定不会丢,一定是 xx 的超集。

所以选法是任意的,只要非空即可。在 g(x)g(x) 中任意选非零个数,选法自然是 2g(x)12^{g(x)} - 1

所以,f(x)=2g(x)1f(x) = 2^{g(x)} - 1

答案要求的是 & 起来为 00 的元素个数。

我们将满足这个条件的子序列称作满足第 ii 个属性:该子序列中所有数 & 起来的值的二进制第 ii 位为 11

我们发现,比如同时满足 i1i_1i2i_2i3i_3 三个属性的子序列数量就对应了 f(2i1or2i2or2i3)f(2^{i_1} \operatorname{or} 2^{i_2} \operatorname{or} 2^{i_3})

那我们要统计的就是不满足任意属性的子序列数量。

根据容斥原理可以得到答案为 x=0Vf(x)×1popcount(x)\sum_{x = 0}^{V} f(x) \times -1^{\operatorname{popcount}(x)}

时间复杂度 Θ(n+VlogV)\Theta(n + V \log V)

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2023-04-18 19:02:58 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2023-04-18 19:23:43
 */
#include <bits/stdc++.h>
#define int long long
inline int read() {
    int x = 0;
    bool f = true;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        if (ch == '-')
            f = false;
    for (; isdigit(ch); ch = getchar())
        x = (x << 1) + (x << 3) + ch - '0';
    return f ? x : (~(x - 1));
}

const int mod = (int)1e9 + 7;
const int lg = 20;
int g[(1 << lg) + 5], pw2[(1 << lg) + 5];

signed main() {
    int n = read();
    for (int i = 1; i <= n; ++i)
        ++g[read()];
    pw2[0] = 1;
    for (int i = 1; i < (1 << lg); ++i)
        pw2[i] = pw2[i - 1] * 2 % mod;
    for (int j = 0; j < lg; ++j) {
        for (int i = (1 << lg) - 1; ~i; --i) {
            if ((i & (1 << j)) == 0) {
                int lst = i ^ (1 << j);
                (g[i] += g[lst]) %= mod;
            }
        }
    }

    int ans = 0;
    for (int x = 0; x < (1 << lg); ++x) {
        (ans += (pw2[g[x]] - 1) * (__builtin_parityll(x) ? -1 : 1) + mod) %= mod;
    }
    printf("%lld\n", ans);
    return 0;
}
posted @   dbxxx  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示