题目:戳这里
题意:A和B博弈,三种操作分别是x:加a,y:减b,z:取相反数。当x或y或z为0,说明该操作不可取,数据保证至少有一个操作可取,给定一个区间(l,k)和原始数字m,如果A和B在n次操作以后使m小于等于l,则B赢,大于等于k则A赢。如果A或B实在赢不了,就会尽量让对方也没法赢。
解题思路:因为数据范围始终在[-100,100],我们就有了逆推的想法。思路是假如n=3且A必赢。因为我们假设的是A必赢,那么第三步之后的m一定在nu3:[k,100]之间,又因为第三步是A的操作,A肯定是哪步操作可以赢,就使用哪步操作,所以第三步以前的范围nu2是根据第三步以后的范围nu3:[k,100]对所有操作逆推出来的集合求并。据此从nu3逆推出nu2。
第三步之间就是第二步,第二步是B的操作,B如果有任何机会肯定是不会让A赢的,所以第二步之前的范围nu1是第二步以后nu2对所有操作逆推出来的集合求交。
nu1同nu3的推法。
第二种情况就是B必赢。也是和上面的思路一样推,如果A必赢和B必赢都无法满足,那一定是在(l,k)之间了。
看代码更好理解。
附ac代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e3 + 10; 4 typedef long long ll; 5 int nu[maxn][11]; 6 int ans[2][555]; 7 int main() 8 { 9 int n, now ,l ,k; 10 scanf("%d %d %d %d", &n, &now, &k, &l); 11 for(int i = 1; i <= n; ++i) 12 { 13 scanf("%d %d %d", &nu[i][1], &nu[i][2], &nu[i][3]); 14 } 15 //B win 16 for(int j = -100; j <= 100; ++j) 17 { 18 if(j <= l) 19 ans[n & 1][j + 200] = 1; 20 else 21 ans[n & 1][j + 200] = 0; 22 } 23 for(int i = n; i >= 1; --i) 24 { 25 memset(ans[(i&1)^1], 0, sizeof(ans[(i&1)^1])); 26 for(int j = -100; j <= 100; ++j) 27 { 28 if(i&1) 29 { 30 int flag = 0; 31 if(nu[i][1]) 32 { 33 int u = min(j + nu[i][1], 100); 34 if(!ans[i&1][u + 200]) flag++; 35 } 36 if(nu[i][2]) 37 { 38 int u = max(j - nu[i][2], -100); 39 if(!ans[i&1][u + 200]) flag++; 40 } 41 if(nu[i][3]) 42 { 43 int u = j * -1; 44 if(!ans[i&1][u + 200]) flag++; 45 } 46 // printf("%d %d %d %d ", i, j, flag, ans[i&1][j + 200]); 47 if(!flag) ans[(i&1) ^ 1][j + 200] = 1; 48 } 49 else 50 { 51 int flag = 0, v = 0; 52 if(nu[i][1]) 53 { 54 ++v; 55 int u = min(j + nu[i][1], 100); 56 if(!ans[i&1][u + 200]) flag++; 57 } 58 if(nu[i][2]) 59 { 60 ++v; 61 int u = max(j - nu[i][2], -100); 62 if(!ans[i&1][u + 200]) flag++; 63 } 64 if(nu[i][3]) 65 { 66 ++v; 67 int u = j * -1; 68 if(!ans[i&1][u + 200]) flag++; 69 70 } 71 // printf("%d %d %d u %d ", i, j, flag == v, l); 72 if(flag != v) ans[(i&1) ^ 1][j + 200] = 1; 73 74 } 75 } 76 } 77 int bwin = 0; 78 for(int i = -100; i <= 100; ++i) 79 { 80 // printf("%d %d ", i, ans[0][i + 200]); 81 if(ans[0][i + 200] && i == now) 82 { 83 ++bwin; 84 break; 85 } 86 } 87 for(int i = -100; i <= 100; ++i) 88 { 89 if(i >= k) 90 ans[n & 1][i + 200] = 1; 91 else 92 ans[n & 1][i + 200] = 0; 93 } 94 95 for(int i = n; i >= 1; --i)//a win 96 { 97 memset(ans[(i&1)^1], 0, sizeof(ans[(i&1)^1])); 98 for(int j = -100; j <= 100; ++j) 99 { 100 if(i & 1) 101 { 102 int flag = 0 ,v = 0; 103 if(nu[i][1]) 104 { 105 ++v; 106 int u = min(j + nu[i][1], 100); 107 if(!ans[i&1][u + 200]) flag++; 108 } 109 if(nu[i][2]) 110 { 111 ++v; 112 int u = max(j - nu[i][2], -100); 113 if(!ans[i&1][u + 200]) flag++; 114 } 115 if(nu[i][3]) 116 { 117 ++v; 118 int u = j * -1; 119 if(!ans[i&1][u + 200]) flag++; 120 } 121 // printf("%d %d %d v %d ", i, j, flag == v, ans[i&1][j + 200]); 122 if(flag != v) ans[(i&1) ^ 1][j + 200] = 1; 123 } 124 else 125 { 126 int flag = 0; 127 if(nu[i][1]) 128 { 129 int u = min(j + nu[i][1], 100); 130 if(!ans[i&1][u + 200]) flag++; 131 } 132 if(nu[i][2]) 133 { 134 int u = max(j - nu[i][2], -100); 135 if(!ans[i&1][u + 200]) flag++; 136 } 137 if(nu[i][3]) 138 { 139 int u = j * -1; 140 if(!ans[i&1][u + 200]) flag++; 141 } 142 // printf("%d %d %d %d ", i, j, flag, ans[i&1][j + 200]); 143 if(!flag) ans[(i&1) ^ 1][j + 200] = 1; 144 } 145 } 146 } 147 int awin = 0; 148 for(int i = -100; i <= 100; ++i) 149 { 150 if(ans[0][i + 200] && i == now) 151 { 152 ++awin; 153 break; 154 } 155 } 156 //printf("%d %d ", awin, bwin); 157 if(!awin && !bwin) puts("Normal Ending"); 158 if(awin) puts("Good Ending"); 159 if(bwin) puts("Bad Ending"); 160 return 0; 161 }