Luogu P2114 起床困难综合症

Luogu P2114 起床困难综合症

由于这道题的三个操作都是位运算,即每一位的贡献都是独立的。所以我们可以按位考虑,即考虑初始攻击力和最后伤害的每一位分别是 $0$ 还是 $1$。

因此我们可以先算出每一位分别取 $0$ 和取 $1$ 在经过所有防御门后最后得到的是什么,然后从高位向低位贪心即可。

需要注意的是(也是被卡了很久 $60$ 分的原因),最后得到的攻击力可能远大于 $m$,其上限应当为 $2 ^ {31} - 1$(因为 $10 ^ {9}$ 对应的二进制有 $30$ 位),因此我们循环的范围不应由 $m$ 的二进制位数确定。

时间复杂度为 $\text{O} (kn)$($k$ 即为攻击力可能的最大位数,本题中为 $30$)。

#include <bits/stdc++.h>
#define N 100010

int n, m;
int op[N], t[N], f[32][2];
long long ans;

namespace WalkerV {
    void Read() {
        scanf("%d %d", &n, &m);
        for (int i = 0; i < n; i++) {
            char tmp[5];
            getchar();
            scanf ("%s %d", tmp, &t[i]);
            switch (tmp[0]) { //or - 1, xor - 2, and - 3
                case 'O':
                    op[i] = 1;
                    break;
                case 'X':
                    op[i] = 2;
                    break;
                case 'A':
                    op[i] = 3;
                    break;
            }
        }
        return;
    }

    void Solve() {
        for (int k = 0; k <= 30; k++) {
            int val = 0;
            for (int i = 0; i <= 1; i++) {
                int tmp = i;
                for (int j = 0; j < n; j++) {
                    switch (op[j]) {
                        case 1:
                            tmp |= ((t[j] >> k) & 1);
                            break;
                        case 2:
                            tmp ^= ((t[j] >> k) & 1);
                            break;
                        case 3:
                            tmp &= ((t[j] >> k) & 1);
                            break;
                    }
                }
                f[k][i] = tmp;
            }
        }
        long long tmp = 0;
        for (int i = 30; i >= 0; i--) {
            if ((f[i][0] < f[i][1]) && (tmp + (1 << i) <= m)) {
                tmp += (1 << i), ans += (f[i][1] << i);
            }
            else {
                tmp += (0 << i), ans += (f[i][0] << i);
            }
        }
        return;
    }

    void Print() {
        printf("%lld\n", ans);
        return;
    }
}

int main()
{
    WalkerV::Read();
    WalkerV::Solve();
    WalkerV::Print();
    return 0;
}
posted @ 2024-09-07 09:17  WalkerV  阅读(3)  评论(0编辑  收藏  举报