1. 程式人生 > 其它 >洛谷P2114-起床困難綜合症

洛谷P2114-起床困難綜合症

題目

21 世紀,許多人得了一種奇怪的病:起床困難綜合症,其臨床表現為:起床難,起床後精神不佳。作為一名青春陽光好少年,atm 一直堅持與起床困難綜合症作鬥爭。通過研究相關文獻,他找到了該病的發病原因:在深邃的太平洋海底中,出現了一條名為 drd 的巨龍,它掌握著睡眠之精髓,能隨意延長大家的睡眠時間。正是由於 drd 的活動,起床困難綜合症愈演愈烈,以驚人的速度在世界上傳播。為了徹底消滅這種病,atm 決定前往海底,消滅這條惡龍。歷經千辛萬苦,atm 終於來到了 drd 所在的地方,準備與其展開艱苦卓絕的戰鬥。drd 有著十分特殊的技能,他的防禦戰線能夠使用一定的運算來改變他受到的傷害。具體說來,drd 的防禦戰線由 n

扇防禦門組成。每扇防禦門包括一個運算 op 和一個引數 t,其中運算一定是 \(OR\),\(XOR\),\(AND\)中的一種,引數則一定為非負整數。如果還未通過防禦門時攻擊力為 x,則其通過這扇防禦門後攻擊力將變為 \(x\space op\space t\)。最終 drd 受到的傷害為對方初始攻擊力 x 依次經過所有 n 扇防禦門後轉變得到的攻擊力。

由於 atm 水平有限,他的初始攻擊力只能為 0 到 m 之間的一個整數(即他的初始攻擊力只能在 \(0,1,...,m\) 中任選,但在通過防禦門之後的攻擊力不受 m 的限制)。為了節省體力,他希望通過選擇合適的初始攻擊力使得他的攻擊能讓 drd 受到最大的傷害,請你幫他計算一下,他的一次攻擊最多能使 drd 受到多少傷害。

思路

最一開始設定兩個數字\(0xFFFFFFFF\)(這個數字大於\(1e9\)並且二進位制下全部為\(1\)即可)和\(0\),對於這兩個數字分別進行一次題目中描述的操作,這樣就得到了真值表。

按照貪心的思想從最高位開始看:

如果當前位\(n\)可以把\(0\)變成\(1\),那肯定是最好的,不佔用\(m\)還能提高攻擊力;否則如果把\(0\)變成\(0\)那麼不必理他即可。

如果當前位\(n\)可以把\(1\)變成\(0\),那這一位設定為\(0\)就行了,因為變成\(1\)不僅佔用\(m\)還減小攻擊力;但如果\(1\)變成\(1\),那麼當\(1<<i\)不超過當前剩餘\(m\)的前提下可以選擇。

程式碼

#include <iostream>
#include <cstring>
#include <string>

typedef long long LL;

std::string s;

void solve() {
    LL n, m, t;
    std::cin >> n >> m;
    LL zeros = 0, ones = 1LL * 0xffffffff;
    for (int i = 0; i < n; i++) {
        std::cin >> s >> t;
        if (s == "AND") {
            zeros &= t;
            ones &= t;
        } else if (s == "OR") {
            zeros |= t;
            ones |= t;
        } else {
            zeros ^= t;
            ones ^= t;
        }
    }
    LL ans = 0;
    for (int i = 30; i >= 0; i--) {
        t = 1LL << i;
        if (zeros & t) {
            ans += t;
        } else if (m >= t && (ones & t)) {
            ans += t;
            m -= t;
        }
    }
    std::cout << ans << std::endl;
}

int main() {
    solve();
    return 0;
}