LightOJ

来源:互联网 发布:淘宝16年被扣24分 编辑:程序博客网 时间:2024/06/05 21:09

传送门:LightOJ - 1199 

题意:有n堆石子,每一堆有xi个,一次操作可以使一堆石子变成两堆数目不相等的石子,最后不能操作的算输,问先手胜还是后手胜。

思路:假设每堆相互独立,那么每堆被分成两堆后就变成了两个独立的游戏,则胜负就可以用nim和(异或)求解。

结合数据范围一看就知道是求sg函数,然而我写了递归版的求sg无限re。。

因为堆每次一分为二必定比原来的小,因此for循环求sg就行了。

其实递归求也可以不过就是递归内的数组要注意大小,可以跑个极限数据发现最大的sg值也就几十,因此数组开到128就够了。

for循环版:

#include<bits/stdc++.h>#define ll long long#define inf 0x3f3f3f3fusing namespace std;typedef pair<int,int> P;const int MAXN = 10010;int sg[MAXN];bool vis[MAXN];void get_sg(){for(int i = 1; i <= 10000; i++){memset(vis, 0, sizeof(vis));int up = i / 2;if(!(i & 1)) up--;for(int j = 1; j <= up; j++)vis[sg[j] ^ sg[i - j]] = 1;for(int j = 0; j < MAXN; j++)if(!vis[j]){sg[i] = j;break;}}}int main(){get_sg();int T, ans, n, t;cin >> T;int kase = 1;while(T--){ans = 0;scanf("%d", &n);for(int i = 0; i < n; i++){scanf("%d", &t);ans ^= sg[t];}printf("Case %d: %s\n", kase++, ans ? "Alice" : "Bob");} return 0;}

递归版:

#include<bits/stdc++.h>#define ll long long#define inf 0x3f3f3f3fusing namespace std;typedef pair<int,int> P;const int MAXN = 10010;int sg[MAXN];int get_sg(int n){if(sg[n] != -1) return sg[n];bool vis[128];memset(vis, 0, sizeof(vis));int up = n / 2;if(!(n & 1)) up--;for(int i = 1; i <= up; i++)vis[get_sg(i) ^ get_sg(n - i)] = 1;for(int i = 0; i < MAXN; i++)if(!vis[i])return sg[n] = i;}int main(){memset(sg, -1, sizeof(sg));sg[0] = sg[1] = sg[2] = 0;int T, ans, n, t;cin >> T;int kase = 1;while(T--){ans = 0;scanf("%d", &n);//n = 100;//int tmp = 0;for(int i = 0; i < n; i++){scanf("%d", &t);//t = 10000;//tmp = max(tmp, get_sg(t));ans ^= get_sg(t);}//cout << tmp << endl;printf("Case %d: %s\n", kase++, ans ? "Alice" : "Bob");} return 0;}


原创粉丝点击