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