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 ightarrow 11 ightarrow 111 ightarrow 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 igoplus a_2 igoplus ··· igoplus a_i)(b[1] = a_1)。满足(b[1] < b[2] < ··· < b[n])

题解

(d)(m) 都超级大,又涉及异或运算,考虑从二进制入手。满足(a)的递增比较简单,重点是怎么确保(b)的递增。有 (b[1] = a_1)(b[2] = a_1 igoplus 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("
");
}

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;
}
原文地址:https://www.cnblogs.com/zgglj-com/p/12654313.html