1 条题解

  • 0
    @ 2026-10-31 17:58:08

    思路

    一次插入只会发生在某个原始间隙 ii(aia_i 与 ai+1a_{i+1} 之间)内部:新元素插进这条间隙后,后续操作可以继续作用在这条间隙里的相邻元素上,而不同间隙之间互不影响。因此只需分别求出每一对相邻数 (x,y)(x,y) 能生成哪些新值,再把这些生成值和原数组元素一起放进 set 去重,set 的大小就是答案。

    下面说明一对 (x,y)(x,y) 最多只能生成 88 个不同的值。与、或、异或都是按位独立运算,所以生成的每个数都是 x,yx,y 的某个按位表达式;又因为

    x∨y=x⊕y⊕(x∧y),x\lor y=x\oplus y\oplus(x\land y),

    或运算可以由异或和与表示,于是所有能生成的数都是不含常数项的多重线性多项式,只有以下 88 种可能:

    $$0,\quad x,\quad y,\quad x\land y,\quad x\oplus y,\quad x\lor y,\quad x\land(y\oplus x),\quad y\land(x\oplus y)$$

    其中 x∧(y⊕x)x\land(y\oplus x) 取出"xx 为 11 而 yy 为 00"的那些位,y∧(x⊕y)y\land(x\oplus y) 取出"yy 为 11 而 xx 为 00"的那些位,00 对应 x⊕xx\oplus x。

    所以对每个间隙做一次 DFS 枚举即可:dfs(l, r, c) 表示对相邻的 l,rl,r 执行第 cc 种操作(11 异或、22 与、33 或),算出结果 tt 后插入集合;若 tt 与 ll 或 rr 相等,说明插入的是重复值,不会产生新的相邻关系,直接剪枝返回;否则继续对 (l,t)(l,t) 和 (t,r)(t,r) 递归。

    递归时的扩展方式需要注意:只有异或操作可以"向左扩展",即继续对 (l,t)(l,t) 做异或;而 dfs(t,r,1) 相当于用异或做逆运算,不属于合法的插入操作,因此不做。与、或操作则对左右两侧都继续扩展。

    候选值最多 88 个,每个间隙的搜索规模是常数,所以整体规模只与输入长度线性相关。

    时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)(set 中存答案)。

    代码

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    
    int n;
    set<int>s;   // 所有出现过的数(原数组元素 + 插入生成的值)
    
    // l:左边的数  r:右边的数  c:操作类型 1:异或 2:与 3:或
    void dfs(int l,int r, int c){
        int t = 0;
        if(c==1){t = l^r;}
        else if(c==2){t = l&r;}
        else{t = l|r;}
    
        s.insert(t);              // 记录新生成的值
        if(t==l or t==r){return;} // 新插入的数和原来的数相等,不会产生新的相邻关系,剪枝
    
        if(c!=1){// 不是异或操作时,还可以继续对它做异或扩展
            dfs(l,t,1);
            // 不能 dfs(t,r,1),那样相当于做异或的逆运算,不是合法插入
        }
        // 继续扩展与和或操作
        dfs(l,t,2);
        dfs(t,r,3);
    }
    
    void go(){
        cin>>n;
        vector<int>a(n+1,0);
    
        for(int i=1;i<=n;i++){
            cin>>a[i];
            s.insert(a[i]);       // 原数组元素本身也算
        }
    
        for(int i=1;i<n;i++){
            for(int j=1;j<=3;j++){// 枚举相邻两个数之间的三种操作
                dfs(a[i], a[i+1], j);
            }
        }
    
        cout<<s.size()<<endl;     // 去重后的个数就是答案
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);cout.tie(nullptr);
        int t=1;
        // 本题只有一组数据,不需要读入测试组数
        while(t--){
            go();
        }
        return 0;
    }
    
    • 1

    信息

    ID
    17
    时间
    1000ms
    内存
    256MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者