UVA1482 Playing With Stones —— SG博弈
题目链接:https://vjudge.net/problem/UVA-1482
题意:
有n堆石子, 每堆石子有ai(ai<=1e18)。两个人轮流取石子,要求每次只能从一堆石子中抽取不多于一半的石子,最后不能取的为输家。
题解:
典型的SG博弈,由于ai的范围很大,所以不能直接求SG值,那么就打表SG值找规律,如下:
发现,当x为偶数时, SG[x] = x/2; 当x为奇数时, SG[x] = SG[x/2],即如下:
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXN = 100+10; 18 19 int SG[MAXN], vis[MAXN]; 20 void table() 21 { 22 SG[0] = SG[1] = 0; 23 for(int i = 2; i<=30; i++) 24 { 25 memset(vis, 0, sizeof(vis)); 26 for(int j = 1; j<=i/2; j++) vis[SG[i-j]] = 1; 27 for(int j = 0;;j++) if(!vis[j]) { 28 SG[i] = j; 29 break; 30 } 31 } 32 33 for(int i = 0; i<=30; i++) printf("%-2d ",i); putchar('\n'); 34 for(int i = 0; i<=30; i++) printf("%-2d ",SG[i]); putchar('\n'); 35 putchar('\n'); 36 for(int i = 0; i<=30; i+=2) printf("%-2d ",i); putchar('\n'); 37 for(int i = 0; i<=30; i+=2) printf("%-2d ",SG[i]); putchar('\n'); 38 putchar('\n'); 39 for(int i = 1; i<=30; i+=2) printf("%-2d ",i); putchar('\n'); 40 for(int i = 1; i<=30; i+=2) printf("%-2d ",SG[i]); putchar('\n'); 41 /* 42 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 43 0 0 1 0 2 1 3 0 4 2 5 1 6 3 7 0 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15 44 45 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 46 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 47 48 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 49 0 0 1 0 2 1 3 0 4 2 5 1 6 3 7 50 */ 51 } 52 53 LL getSG(LL x){ 54 return x%2==0?x/2:getSG(x/2); 55 } 56 57 int main() 58 { 59 // table(); 60 int T, n; 61 scanf("%d", &T); 62 while(T--) 63 { 64 LL a, v = 0; 65 scanf("%d", &n); 66 for(int i = 1; i<=n; i++) 67 { 68 scanf("%lld", &a); 69 v ^= getSG(a); 70 } 71 72 if(v) printf("YES\n"); 73 else printf("NO\n"); 74 } 75 }