ACM-ICPC 2018 徐州賽區網絡預賽 B BE, GE or NE 【模擬+博弈】


題目:戳這里

題意: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\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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 }
View Code

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com