牛客多校2021(八)D. OR(位运算)

  • 题目:OR

  • 题意:给出一个长度为(n - 1)的序列\(b_i\)\(c_i\),问存在多少个a序列,满足所有(\(1 \leq i\leq n\))

    \[\begin{align*} a_{i-1}|a_i = b_i, \ a_{i-1}+a_i = c_i \end{align*} \]

  • 解析:有如下性质并可以进行推导:

    \[\begin{align*} & a_{i-1}+a_i = a_{i-1}|a_i + a_{i-1}\&a_i \\ & \because b_i = a_{i-1} | a_i\\ & \therefore 令d_i = c_i - b_i = a_{i-1}\&a_i \\ & 即:a序列(1 \leq i \leq n)满足:a_{i-1}|a_i = b_i, \ a_{i-1}\&a_i = d_i 即可\\ \end{align*} \]

    并且我们可以发现,只要\(a_1\)确定之后,之后的\(a_i\)一定是确定的(\(a_i\)\(b_i\)\(c_i\)​决定),那么我们可以通过枚举int范围内的\(a_1\)也就是枚举其每一位是否可以为0或者为1,每一位至多有两种方案,最后用乘法原理将所有方案数相乘即可,下面是枚举到第\(k\)位时的情况:

    \(b_i\)​​ \(d_i\)​​ \(a_i\) \(a_{i-1}\)
    0 0 0 0
    1 1 1 1
    1 0 1 0
    0 1
    0 1 null null

    举个例子:当\(b_i\) = 0, \(d_i\) = 0时候,若要满足上诉条件必须使得\(a_i\) = 0, \(a_{i-1}\) = 0才能满足,否则若\(a_{i-1}\)​ = 1, 那么这种方案则不存在。​

  • 代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 5;
    
    int n;
    int b[N], c[N], d[N];
    ll res = 1;
    
    ll solve(int pos, int k, int pre) //第pos个数、第pos个数的第k位、a[pos - 1]的第k位
    {
        if(pos > n) return 1;
        int x = b[pos] >> k & 1, y = d[pos] >> k & 1; //取出第pos个数的第k位
        int now = -1; //第k + 1位取的值(1或0)
        for(int i = 0; i <= 1; i++) //判断ai = 0/1是否满足条件(只可能是其中之一满足,因为a(i-1)已经确定)
        {
            if(x == (pre | i) && y == (pre & i) ) now = i;
        }
        if(now == -1) return 0; //找不到满足条件的ai
        else return solve(pos + 1, k, now);
    }
    
    int main()
    {
        cin >> n;
        for(int i = 2; i <= n; i++) cin >> b[i];
        for(int i = 2; i <= n; i++)
        {
            cin >> c[i];
            d[i] = c[i] - b[i];
        }
        for(int i = 0; i <= 31; i++)
        {
            res *= solve(2, i, 0) + solve(2, i, 1);
        }
        cout << res << endl;
        return 0;
    }
    
    
posted @ 2021-08-11 09:38  ~K2MnO4  阅读(79)  评论(0)    收藏  举报