P2114 [NOI2014]起床困難綜合症
題目描述
21世紀,許多人得了一種奇怪的病:起床困難綜合症,其臨床表現為:起床難,起床後精神不佳。作為一名青春陽光好少年,atm一直堅持與起床困難綜合症作鬥爭。
通過研究相關文獻,他找到了該病的發病原因: 在深邃的太平洋海底中,出現了一條名為drd的巨龍,它掌握著睡眠之精髓,能隨意延長大家的睡眠時間。
正是由於drd的活動,起床困難綜合症愈演愈烈, 以驚人的速度在世界上傳播。為了徹底消滅這種病,atm決定前往海底,消滅這條惡龍。歷經千辛萬苦,
atm終於來到了drd所在的地方,準備與其展開艱苦卓絕的戰鬥。drd有著十分特殊的技能,他的防禦戰線能夠使用一定的運算來改變他受到的傷害。具體說來
,drd的防禦戰線由n扇防禦門組成。每扇防禦門包括一個運算op和一個引數t,其中運算一定是OR,XOR,AND中的一種,引數則一定為非負整數。
如果還未通過防禦門時攻擊力為x,則其通過這扇防禦門後攻擊力將變為x op t。最終drd受到的傷害為對方初始攻擊力x依次經過所有n扇防禦門後轉變得到的攻擊力。
由於atm水平有限,他的初始攻擊力只能為0到m之間的一個整數(即他的初始攻擊力只能在 0, 1, … , m中任選,但在通過防禦門之後的攻擊力不受m的限制)。
為了節省體力,他希望通過選擇合適的初始攻擊力使得他的攻擊能讓drd受到最大的傷害,請你幫他計算一下,他的一次攻擊最多能使drd受到多少傷害。
輸入格式
輸入檔案的第 1 行包含 2 個整數,依次為n, m,表示 drd 有n扇防禦門,atm 的初始攻擊力為0到m之間的整數。
接下來n行,依次表示每一扇防禦門。每行包括一個字串op和一個非負整數t,兩者由一個空格隔開,且op在前,t在後,op表示該防禦門所對應的操作,t表示對應的引數。
輸出格式
輸出一行一個整數,表示atm的一次攻擊最多使drd受到多少傷害。
輸入輸出樣例
輸入 #1
3 10
AND 5
OR 6
XOR 7
輸出 #1
1
說明/提示
【樣例說明】
atm可以選擇的初始攻擊力為 0,1, … ,10。
假設初始攻擊力為 4,最終攻擊力經過了如下計算
4 AND 5 = 4
4 OR 6 = 6
6 XOR 7 = 1
類似的,我們可以計算出初始攻擊力為 1,3,5,7,9 時最終攻擊力為 0,初始攻擊力為 0,2,4,6,8,10 時最終攻擊力為 1,因此atm的一次攻擊最多使drd受到的傷害值為1。
【資料規模與約定】
首先,我們可以貪心,答案要儘可能最高位要是1。
那我們原來得數這一位為1的話,要滿足兩個條件
- 從這一位開始,後面都填0的話要小於m。
2.填1的得到的結果要比填0要優
這樣,我們可以列舉一開始這個數的每一位。
對他的這一位分別進行運算,看填1還是填0要優
程式碼
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
return s * w;
}
string opt;
int n,m,shu,ans,t;
struct node
{
string opt;
int t;
}e[100010];
int calc(int wei,int val)
{
for(int i = 1; i <= n; i++)
{
int x = (e[i].t>>wei) & 1;//取出每個運算元的第i位,並進行操作
if(e[i].opt == "OR") val |= x;
else if(e[i].opt == "AND") val &= x;
else val ^= x;
}
return val;
}
int main()
{
n = read(); m = read();
for(int i = 1; i <= n; i++)
{
cin>>opt; t = read();//先把所有操作都存起來
e[i].opt = opt;
e[i].t = t;
}
for(int i = 30; i >= 0; i--)//列舉每一位
{
int f1 = calc(i,0);//計算填0的結果
int f2 = calc(i,1);//計算填1的結果
if(shu+(1<<i) <= m && f1 < f2)//shu位當前已經填好的數,如果這個數填了1以後,
// 後面的位填0都要比m大,那我們就不可以填1,只能填0
{
shu += (1<<i);//一開始的數這一位填1更優
ans += (f2<<i);//填1得到的結果
}
else shu += (0<<i), ans += (f1<<i);
}
printf("%d\n",ans);
return 0;
}