1. 程式人生 > >bzoj3668: [Noi2014]起床困難綜合症 拆位模擬

bzoj3668: [Noi2014]起床困難綜合症 拆位模擬

bzoj3668: [Noi2014]起床困難綜合症

Description

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 受到多少傷害。

Input

第1行包含2個整數,依次為n,m,表示drd有n扇防禦門,atm的初始攻擊力為0到m之間的整數。接下來n行,依次表示每一扇防禦門。每行包括一個字串op和一個非負整數t,兩者由一個空格隔開,且op在前,t在後,op表示該防禦門所對應的操作, t表示對應的引數。n<=10^5

Output

一行一個整數,表示atm的一次攻擊最多使 drd 受到多少傷害。

Sample Input

3 10
AND 5
OR 6
XOR 7

Sample Output

1

HINT

【樣例說明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。
0<=m<=10^9
0<=t<=10^9
一定為OR,XOR,AND 中的一種
【運算解釋】
在本題中,選手需要先將數字變換為二進位制後再進行計算。如果操作的兩個數二進位制長度不同,則在前補0至相同長度。OR為按位或運算,處理兩個長度相同的二進位制數,兩個相應的二進位制位中只要有一個為1,則該位的結果值為1,否則為0。XOR為按位異或運算,對等長二進位制模式或二進位制數的每一位執行邏輯異或操作。如果兩個相應的二進位制位不同(相異),則該位的結果值為1,否則該位為0。 AND 為按位與運算,處理兩個長度相同的二進位制數,兩個相應的二進位制位都為1,該位的結果值才為1,否則為0。
例如,我們將十進位制數5與十進位制數3分別進行OR,XOR 與 AND 運算,可以得到如下結果:
0101 (十進位制 5) 0101 (十進位制 5) 0101 (十進位制 5)
OR 0011 (十進位制 3) XOR 0011 (十進位制 3) AND 0011 (十進位制 3)
= 0111 (十進位制 7) = 0110 (十進位制 6) = 0001 (十進位制 1)

分析

一眼秒拆位,每位帶0或1進去看看結果是1還是0,然後貪心即可。
然而實際上有一種更妙的做法。因為位運算本來就是按位獨立的。所以可以直接把 11111 11111\cdots 00000

00000\cdots 拿去操作一波。出來的時候看一下每位變成了什麼即可。
貪心類似數位Dp
時間複雜度 O ( n ) O(n) ,空間複雜度 O ( 1 ) O(1)

程式碼

#include<bits/stdc++.h>
int ri() {
    char c = getchar(); int x = 0; for(;c < '0' || c > '9'; c = getchar()) ;
    for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x;
}
int main() {
    int n = ri(), m = ri(), b0 = 0, A = 0, b1 = 0x7fffffff;
    for(int i = 1;i <= n; ++i) {
        char op = getchar(); for(;op != 'A' && op != 'O' && op != 'X'; op = getchar()) ;
        int x = ri();
        if(op == 'A') b0 &= x, b1 &= x;
        if(op == 'O') b0 |= x, b1 |= x;
        if(op == 'X') b0 ^= x, b1 ^= x;
    }
    for(int i = 31; ~i; --i) {
        bool t0 = (b0 >> i) & 1, t1 = (b1 >> i) & 1;
        if(t0 >= t1 || m <= (1 << i)) A |= t0 ? 1 << i : 0;
        else A |= t1 ? 1 << i : 0, m -= 1 << i;
    }
    printf("%d\n", A);
    return 0;
}