起床困难综合征(位运算)
具體說來,drd 的防御戰(zhàn)線由 nn 扇防御門組成。每扇防御門包括一個運(yùn)算 opop 和一個參數(shù) tt,其中運(yùn)算一定是 OR,XOR,AND 中的一種,參數(shù)則一定為非負(fù)整數(shù)。如果還未通過防御門時攻擊力為 x,則其通過這扇防御門后攻擊力將變?yōu)?x op t。最終 drd 受到的傷害為對方初始攻擊力 x 依次經(jīng)過所有 nn 扇防御門后轉(zhuǎn)變得到的攻擊力。
由于 atm 水平有限,他的初始攻擊力只能為 0 到 m 之間的一個整數(shù)(即他的初始攻擊力只能在 0,1,…,m 中任選,但在通過防御門之后的攻擊力不受 m 的限制)。為了節(jié)省體力,他希望通過選擇合適的初始攻擊力使得他的攻擊能讓 drd 受到最大的傷害,請你幫他計(jì)算一下,他的一次攻擊最多能使 drd 受到多少傷害。
輸入格式
輸入文件的第 1 行包含 2 個整數(shù),依次為 n,m,表示 drd 有 n 扇防御門,atm 的初始攻擊力為 0 到 m 之間的整數(shù)。
接下來 n 行,依次表示每一扇防御門。每行包括一個字符串 op 和一個非負(fù)整數(shù) t,兩者由一個空格隔開,且 op 在前,t在后,op 表示該防御門所對應(yīng)的操作,t 表示對應(yīng)的參數(shù)。
輸出格式
輸出一行一個整數(shù),表示 atm 的一次攻擊最多使 drd 受到多少傷害。
輸入輸出樣例
輸入 #1復(fù)制
3 10
AND 5
OR 6
XOR 7
輸出 #1復(fù)制
1
說明/提示
【樣例說明】
atm 可以選擇的初始攻擊力為 0,1,…,10。
假設(shè)初始攻擊力為 4,最終攻擊力經(jīng)過了如下計(jì)算
4 AND 5=4
4 OR 6=6
6 XOR 7=1
類似的,我們可以計(jì)算出初始攻擊力為 1,3,5,7,9 時最終攻擊力為 0,初始攻擊力為 0,2,4,6,8,10 時最終攻擊力為 1,因此atm的一次攻擊最多使drd受到的傷害值為 1。
2 <=n<=10 ^ 5,2<=m<=10 ^ 9
知識點(diǎn):
1、與1異或,可以使特定位翻轉(zhuǎn) ,與0異或,保留其值 0101 0101 ^ 1111 0000 = 1010(翻轉(zhuǎn)) 0101(保留)
2、相同的值異或?yàn)? a^a=0
3、1除了最低位,其他位都為0,所以按位與結(jié)果取決于n最后一位,如果n最后一位是1,則結(jié)果為1,反之結(jié)果為0
4、0的二進(jìn)制是: 00000000…………
-1的二進(jìn)制是:1111111111…………
只用0和-1進(jìn)行位運(yùn)算,就可以得到任何一位的任何情況進(jìn)行位運(yùn)算的結(jié)果
思路:
1、目的是從(0,m)中選出一個最好的初始攻擊數(shù)據(jù)K,然后通過n道門之后,數(shù)最大
2、如果把m中的每個數(shù)據(jù)都枚舉一遍,肯定不可以,所以反向思考得到最佳數(shù)據(jù)
3、過程肯定是將初始值K,攻擊n道門,將K轉(zhuǎn)化成二進(jìn)制后,其實(shí)也就是二進(jìn)制數(shù)上的每一位數(shù)都攻擊過n道門(位運(yùn)算的性質(zhì),每個數(shù)之間相互不影響)
可以通過一個函數(shù):
4、接下來就是把所有二進(jìn)制位數(shù)遍歷一遍,因?yàn)楸绢}中 m 最大是 10 ^ 9,log2(10 ^ 9) < 30,最多30位
5、當(dāng)前數(shù)字一定是0 或 1,判斷,誰合適當(dāng)前位就填誰
完整代碼:
#include <iostream> #include <vector> #include <algorithm> #include <cmath> #include <cstring> #include <cstdio> #include <iomanip>using namespace std; typedef long long ull; ull n,m,k,c,sum=0,x; int t[100005]; // t 存輸入的 n 個數(shù) string op[100005]; // op 存 n 個數(shù)對應(yīng)的操作 bool jisuan(bool x, int j) // jisuan 用于計(jì)算 x 經(jīng)過所有數(shù)的第 j 位操作后所得到的結(jié)果 {for (int i = 0; i < n; i ++ ) // 當(dāng)前數(shù)字,遍歷n道門if (op[i] == "OR") x |= t[i] >> j & 1;else if (op[i] == "XOR") x ^= t[i] >> j & 1;else x &= t[i] >> j & 1;return x; } int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=0; i<n; i++){cin>>op[i]>>t[i];}for(int i=29; i>=0; i--){bool x = jisuan(0, i), y = jisuan(1, i); if (m >> i && x<y) {sum |= y << i; m -= 1 << i; }else sum |= x << i; }cout<<sum<<endl;return 0; }下面是一個更技巧的寫法,真神奇
利用:
0的二進(jìn)制是: 00000000…………
-1的二進(jìn)制是:1111111111…………
只用0和-1進(jìn)行位運(yùn)算,就可以得到任何一位的任何情況進(jìn)行位運(yùn)算的結(jié)果
我們本來是循環(huán)一次就判斷一次n道門后,0和1誰更合適
令a=0,b=-1, 把函數(shù)省掉,不用每次都判斷當(dāng)前這位數(shù)經(jīng)過n道門之后的結(jié)果,在輸入的時候直接保存了每一位數(shù)的結(jié)果
總結(jié)
以上是生活随笔為你收集整理的起床困难综合征(位运算)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GC---G1
- 下一篇: iOS App的推广渠道追踪