1. 程式人生 > 其它 >AcWing 998. 起床困難綜合症

AcWing 998. 起床困難綜合症

解法思想:

位運算只關注當前進行運算的一位,對其他位無影響。對於輸入的初始攻擊x,需要進行n次op運算,得到最大攻擊力。把最後的輸出以二進位制表示,即我們希望輸出的最大攻擊力有儘可能多的1。


對於初始攻擊x,假設一共有k位,每一位只有0或1兩種取值。我們把每一位單獨拿出來做n次運算。來確定該位應該填0還是1。依次從高位到低位確定。


比如:對於一個4位的數_ _ _ _,我們需要進行3次op運算,假設最高位第3位分別是0或1的兩種情況,op[i]運算對應引數為t[i],則對t[i]>>3&1,這裡我們只關心引數t[i]對應需要運算的一位,其他全部置0,所以與1進行與運算。0和1分別做完n次運算後的結果為res0和res1,誰大取誰,對res<<3得到最大攻擊力該位的數值。其他位計算同理。


這裡還有兩個約束條件:
1.若res0<res1,我們需要保證當初始攻擊該位取1時不超過初始攻擊上限m。
2.若res0>res1,該位取0。
————————————————
原文連結:https://blog.csdn.net/weixin_45774311/article/details/120827430

https://www.acwing.com/solution/content/15383/




/*
按位或:OR 為按位或運算,處理兩個長度相同的二進位制數,兩個相應的二進位制位中只要有一個為 1,則該位的結果值為 1,否則為 0。運算子 (|) 按位異或:XOR 為按位異或運算,對等長二進位制模式或二進位制數的每一位執行邏輯異或操作。如果兩個相應的二進位制位不同(相異),則該位的結果值為 1,否則該位為 0。運算子(^)。 按位與:AND 為按位與運算,處理兩個長度相同的二進位制數,兩個相應的二進位制位都為 1,該位的結果值才為 1,否則為 0。運算子(&)。 取反運算:參加運算的一個數據,按二進位制位進行“取反”運算。運算子(~)。 左移運算:將一個運算物件的各二進位制位全部左移若干位(左邊的二進位制位丟棄,右邊補0)。左移一位相當於該數乘以2。運算子(<<)。 右移運算:將一個數的各二進位制位全部右移若干位,正數左補0,負數左補1,右邊丟棄。右移一位相當於該數除以2。運算子(>>)。
*/ #include<stdio.h> const int N=100005; int n,m; int ans; int t[N]; short op[N]; char str[4]; bool calc(bool x,int j) { for(int i=0;i<n;i++) { if(op[i]==1) x|=t[i]>>j&1; else if(op[i]==2) x^=t[i]>>j&1; else x&=t[i]>>j&1; }
return x; } int main() { scanf("%d %d",&n,&m); for(int i=0;i<n;i++) { scanf("\n%s %d",str,t+i); if(*str=='O') op[i]=1; else if(*str=='X') op[i]=2; else op[i]=3; } for(int i=29;~i;i--) { if(1<<i<=m) { bool x=calc(0,i),y=calc(1,i); if(x>=y) ans|=x<<i; else ans|=y<<i,m-=1<<i; } else ans|=calc(0,i)<<i; } printf("%d\n",ans); return 0; }