codeforce刷题

codeforce 1332D Walk on Matrix

题目: https://vjudge.net/problem/CodeForces-1332D

题解

切入点是找出题目所给算法的错误之处,也就是每一次取最优解,但结果可能不是最优解的情况。比如:

111  100    0
11   111   11

按照给出的算法,\(dp[2][2] = 100_{(2)} = 4\),而\(dp[2][3] = 0_{(2)} = 0\),也就是在\(dp\)过程中,每次都取了最高位为1作为当前最优解。实际上,选择 \(111 \rightarrow 11 \rightarrow 111 \rightarrow 11\), 得到\(maxAnd = 11_{(2)} = 3\)
构造出这样的样例后,将\(11_{(2)}\)换成\(k\)的二进制,写出矩阵就行啦

const int MAXN = 200005;

int get(int x, int op) {
    int t = 0, tp = x;
    while(tp) {
        tp >>= 1;
        t++;
    }
    if (op == 0) {
        return (1 << t) + (~x & ((1 << t) - 1));
    }
    else {
        return (1 << t) + x;
    }
}

int main() {

    int k; cin >> k;

    int a[2][3] = {{get(k, 1), get(k, 0), 0}, {k, get(k, 1), k}};
    cout << "2 3" << endl;
    myfor(i, 0, 2) {
        myfor(j, 0, 3) printf("%d ", a[i][j]);
        cout << endl;
    }
    return 0;
}

整麻烦了,看这位大佬的构造:https://blog.csdn.net/weixin_42431507/article/details/105236247?>

CodeForces 1329B Dreamoon Likes Sequences

给两个数\(d(1 <= d <= 10^9)\)\(m(1 <= m <= 10^9)\),问有多少种满足如下条件的\(a\)序列?方案数要模上\(m\)

  • \(a\)序列的长度为\(n\) \((1<= n <= d)\)
  • \(1 <= a_1 < a_2 < ··· < a_n <= d\)
  • \(b[i] = a_1 \bigoplus a_2 \bigoplus ··· \bigoplus a_i\)\(b[1] = a_1\)。满足\(b[1] < b[2] < ··· < b[n]\)

题解

\(d\)\(m\) 都超级大,又涉及异或运算,考虑从二进制入手。满足\(a\)的递增比较简单,重点是怎么确保\(b\)的递增。有 \(b[1] = a_1\)\(b[2] = a_1 \bigoplus a_2\)\(a_2 > a_1\),那么\(b[2] > b[1]\)说明\(a_2\)的二进制长度大于\(a_1\)的二进制长度。以此递推,可以发现,\(a\)序列中元素的二进制长度是递增的,所以\(a\)的元素个数最多30个(\(2^{30} > 10^9\)).
将二进制长度相同的数划分为1组(比如4,5,6,7的二进制长度都是3,归为一组),然后每组只能取一个数,求方案数。举例来说:\(d = 5\),共有三组:\((1)\)\((2, 3)\)\((4, 5)\)。令\(ans_n :=\)表是长度为\(n\)且符合条件的\(a\)序列个数,根据组合数学的知识可得 \(ans_1 = 5\)\(ans_2 = 1 * 2 + 1 * 2 + 2 * 2 = 8\)\(ans_3 = 1 * 2 * 2 = 4\)。求得总的方案数: \(ans = ans_1 + ans_2 + ans_3 = 17\)
最后,思考怎么\(code\)。硬搜肯定复杂度超了,令\(dp[i][j]:=\)\(i\)个组选择\(j\)个数的方案数,有

\[ dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] * cnt[i] \]

注意爆int

int bit_length(int x) {
    int t = 0;
    while(x) {t++, x >>= 1; }
    return t;
}

void Inite() {
    memset(cnt, 0, sizeof(cnt));
    memset(dp, 0, sizeof(dp));

    group = bit_length(d);
    for (int i = 1; i < group; ++i) cnt[i] = 1 << (i - 1), d -= cnt[i];
    cnt[group] = d;

    //for (int i = 1; i <= group; ++i) printf("%d ", cnt[i]);
    //printf("\n");
}

void Solve() {
    cin >> d >> mod;

    Inite();

    for (int i = 1; i <= group; ++i) for (int j = 1; j <= i; ++j) {
        if (j == 1) dp[i - 1][j - 1] = 1;
        dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * cnt[i] % mod) % mod;
    }

    long long ans = 0;
    for (int i = 1; i <= group; ++i) ans = (ans + dp[group][i]) % mod;
    cout << ans << endl;
}
posted @ 2020-04-07 16:52  天之道,利而不害  阅读(347)  评论(0)    收藏  举报