1 条题解

  • 0
    @ 2025-8-24 22:29:21

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar do_while_true

    搬运于2025-08-24 22:29:21,当前版本为作者最后更新于2021-02-07 21:16:29,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    官方题解。

    Subtask 11:直接爆搜。

    Subtask 22:留给一些看起来很对的乱搞。

    Subtask 33:所有的 00 都能单独分,所有的 11 必须分在一组,因为如果把 11 分开的话按位或的和会增大。故答案为 00 的个数,若出现 11 则还要 +1+1

    Subtask 44:猜答案,为 11。考虑完 Subtask 55 的做法,由于数据随机,这些二进制位很容易连通起来。

    Subtask 55:对于一个数的第 xx 位为 11,则所有第 xx 位为 11 的都要分在一起,若分开这个二进制位会被统计两次。这样每个数会把一些二进制位链接起来,这些链接起来的肯定要放在一起。二进制拆位之后并查集求解即可。复杂度 O(nloga)\mathcal{O}(n\log a)

    Subtask 66:只有 6060 个位置,直接并查集太浪费了。考虑用一个 ull 来表示状态,每次需要合并的时候才合并。最多合并 6060 次,每次合并共 6060 次。复杂度 O(n+602)\mathcal{O}(n+60^2)

    至此,问题解决。

    #include<iostream>
    #include<cstdio>
    #define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    #define ull unsigned long long
    char buf[1<<21],*p1=buf,*p2=buf;
    template <typename T>
    inline T& read(T& r) {
        r = 0; bool w = 0; char ch = getchar();
        while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
        while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
        return r = w ? -r : r;
    }
    const int N = 1000100;
    int n, ans;
    ull f[64], all;
    signed main() {
        read(n);
        for(int i = 1; i <= 61; ++i) f[i] = 1ll << (i-1);
        for(int i = 1; i <= n; ++i) {
            ull x; read(x);
            if(!x) {
                ++ans;
                continue;
            }
            all |= x;
            int p = __builtin_ffsll(x); ull t = f[p] | x;
            if(t == f[p]) continue;
            for(int j = 1; j <= 61; ++j)
                if((1ll << (j-1)) & t)
                    t |= f[j];
            for(int j = 1; j <= 61; ++j)
                if((1ll << (j-1)) & t)
                    f[j] |= t;
        }
        for(int i = 1; i <= 61; ++i)
            if((1ll << (i-1)) & all)
                if(f[i]) {
                    ++ans; ull t = f[i];
                    for(int j = 1; j <= 61; ++j)
                        if((1ll << (j-1)) & t)
                            f[j] = 0;
                }
        printf("%d\n", ans);
        return 0;
    }
    
    • 1

    信息

    ID
    5984
    时间
    400~1000ms
    内存
    250MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者