看到这道题,分析后第一反应是取1的数最大的数,很明显我是忽略了 XOR 可以把0变成1的可能性。 后来想了想,又看了别人的题解后发现。这二进制的变换中每一位都是互相独立的,因为每一个数都只有两种初始状态和终止状态。即一开始为0的二进制位经过多次变换后可能为1或者为0, 为1的二进制位经过变换后也有可能变为1或0, 很明显,如果一开始为0的二进制位经过多次变换后变成了1,那么我们优先选择该二进制位的初始状态为0,如果不成立,如果一开始为1的二进制经过多次变换后可以变成1,且该数小于 m, 那么我们也可以将其初始状态设为1,若该二进制位无论0或1,最终都只是0,那么我们将其赋值为0.很显然,用两个数一个是0,一个是2的31次方减1, 去进行多次变换后看两者的值进行舍取得到最终的答案。
经验教训:
1:盲目认为0xfffffff 是2的31次方-1. WA了几次。
2:一开始在于初始状态为0的二进制位上认为要小于m,WA了几次。
心酸啊!
启发,有时候把一些复杂的题中各部分独立出来,一个个去解决。当然前提也是这道题中各部分不会相互影响。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #define rep(i,j,k) for(int i = j; i <= k; i++) 5 #define down(i,j,k) for(int i = j; i >= k; i--) 6 #define LL long long 7 using namespace std; 8 LL num = pow(2,31)-1; 9 LL num2 = 0; 10 11 int read() 12 { 13 int s = 0, t = 1; char c = getchar(); 14 while( !isdigit(c) ){ 15 if( c == '-' ) t = -1; c = getchar(); 16 } 17 while( isdigit(c) ){ 18 s = s * 10 + c - '0'; c = getchar(); 19 } 20 return s * t; 21 } 22 23 int main() 24 { 25 int n = read(), m = read(); 26 char c[5] = {0}; 27 rep(i,1,n){ 28 scanf("%s", &c); 29 int x = read(); 30 if( c[0] == 'A' ){ 31 num &= x; 32 num2 &= x; 33 } 34 if( c[0] == 'X' ){ 35 num ^= x; 36 num2 ^= x; 37 } 38 if( c[0] == 'O' ){ 39 num |= x; 40 num2 |= x; 41 } 42 } 43 LL ans = 0; 44 down(i,31,0){ 45 if( (num2 & (1<<i)) ){ 46 ans += (1 << i); 47 } 48 else if( (num & (1<<i)) && ((1<<i) <= m) ){ 49 m -= (1 << i); 50 ans += (1 << i); 51 } 52 } 53 cout<<ans<<endl; 54 return 0; 55 }
3668: [Noi2014]起床困难综合症
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1164 Solved: 660
[Submit][Status][Discuss]
Description
Input
第1行包含2个整数,依次为n,m,表示drd有n扇防御门,atm的初始攻击力为0到m之间的整数。接下来n行,依次表示每一扇防御门。每行包括一个字符串op和一个非负整数t,两者由一个空格隔开,且op在前,t在后,op表示该防御门所对应的操作, t表示对应的参数。
Output
一行一个整数,表示atm的一次攻击最多使 drd 受到多少伤害。
Sample Input
AND 5
OR 6
XOR 7