CF 1557 C. Moamen and XOR

C. Moamen and XOR

题目大意

给定\(n,k\),要求创建一个\(n\)个数的数组\(a\),满足\(0 \leq a_i < 2^k\),且\(a_1 \,\&\, a_2 \,\&\, a_3 \,\&\, \ldots \,\&\, a_n \ge a_1 \oplus a_2 \oplus a_3 \oplus \ldots \oplus a_n\),问方案数。

解题思路

简单\(DP\)

从高位考虑,设\(dp[i]\)表示前\(i\)位满足条件的方案数,根据\(n\)的奇偶性,考虑与结果\(i\)位为\(0\)\(1\)时的转移即可。

  • \(n\)为奇数
    • 与结果第\(i\)位为\(1\),则异或结果也为\(1\),此时\(dp[i] += dp[i - 1]\)
    • 与结果第\(i\)位为\(0\),则要使异或结果也为\(0\),第\(i\)位填法有\(C_n^0 + C_n^2 + C_n^4 + ... + C_n^{n-1} = 2^{n-1}\),此时\(dp[i] += 2^{n-1}dp[i - 1]\)
    • \(dp[i] = dp[i - 1] + 2^{n-1}dp[i-1]\)
  • \(n\)为偶数
    • 与结果第\(i\)位为\(1\),则异或结果为\(0\),剩下\(i-1\)位随便填,此时\(dp[i] += 2^{(i-1)n}\)
    • 与结果第\(i\)位为\(0\),则要使异或结果也为\(0\),第\(i\)位填法有\(C_n^0 + C_n^2 + C_n^4 + ... + C_n^{n - 2} = 2^{n-1} - 1\),此时\(dp[i] += (2^{n-1} - 1)\times dp[i - 1]\)(除去\(C_n^n\)即全为1的填法,因为此时与结果为1)
    • \(dp[i] = 2^{(i-1)n} + (2^{n-1} - 1) \times dp[i-1]\)
神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

template <typename T>
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template <typename T, typename... rest>
void read(T &x, rest&... Rest) {
    read(x);
    read(Rest...);
}

template <typename T>
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

const LL mo = 1e9 + 7;
const int N = 2e5 + 8;

int n, k;

LL dp[N], p2[N];

LL qpower(LL a, LL b){
    LL qwq = 1;
    while(b){
        if (b & 1)
            qwq = qwq * a % mo;
        a = a * a % mo;
        b >>= 1;
    }
    return qwq;
}

int main(void) {
    int kase; read(kase);
    p2[0] = 1;
    for(int i = 1; i < N; ++ i)
        p2[i] = p2[i - 1] * 2 % mo;
    for (int ii = 1; ii <= kase; ii++) {
        read(n, k);
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        for(int i = 1; i <= k; ++ i)
            if (n & 1){
                dp[i] = (dp[i - 1] + p2[n - 1] * dp[i - 1] % mo) % mo;
            }else{
                dp[i] = (qpower(p2[i - 1], n) + (p2[n - 1] - 1) * dp[i - 1] % mo) % mo;
            }
        write(dp[k], '\n');
    }
    return 0;
}


posted @ 2021-09-08 11:16  ~Lanly~  阅读(56)  评论(0编辑  收藏  举报