题目传送:Division Game
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
const int maxn = 10005;
int n, m, t;
int match[55];//把一行的若干个数都变为他们的真因子,即拿掉了一些素因子,即可以看成一堆火柴中取出几根来,所以可以看做Nim类组合游戏
int chu[maxn];
int to[maxn];//计算出每个数字的素因子个数
void init() {//打表计算素因子
to[1] = 0;
for(int i = 2; i < maxn; i ++) chu[i] = i;
for(int i = 2; i < maxn; i ++) {
if(to[i]) continue;
to[i] ++;
for(int j = 2 * i; j < maxn; j += i) {
while(chu[j] % i == 0) {
to[j] ++;
chu[j] /= i;
}
}
}
}
int main() {
init();
int T;
scanf("%d", &T);
for(int cas = 1; cas <= T; cas ++) {
memset(match, 0, sizeof(match));
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
scanf("%d", &t);
match[i] += to[t];
}
}
//因为题目可以看做Nim游戏,所以sg数值即为火柴数值的异或和
int sg = match[1];
for(int i = 2; i <= n; i ++) {
sg = sg ^ match[i];
}
if(sg == 0) printf("Case #%d: NO\n", cas);//sg为0时先手必败,反之必胜
else printf("Case #%d: YES\n", cas);
}
return 0;
}
题目传送:Playing With Stones
此题可以先打表来找规律。
打表代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
const int maxn = 100;
int SG[maxn];
int vis[maxn];
int main() {
SG[1] = 0;//只有一个的时候不能拿,为必败状态
for(int i = 2; i <= 30; i ++) {
memset(vis, 0, sizeof(vis));
for(int j = 1; j * 2 <= i; j ++) vis[SG[i-j]] = 1;
for(int j = 0;; j++) if(!vis[j]) {
SG[i] = j;
break;
}
printf("%d ", SG[i]);
}
return 0;
}
规律为:
n为偶数时,SG(n) = n / 2;
n为奇数时,SG(n) = SG(n/2);
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
LL SG(LL x) {
return (x & 1) ? SG(x / 2) : x / 2;
}
int main() {
int T;
cin >> T;
while(T --) {
int n;
LL a, ans = 0;
cin >> n;
for(int i = 0; i < n; i ++) {
cin >> a;
ans ^= SG(a);
}
if(ans) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
题目传送:Treblecross
昨晚没睡好,然后着凉了,加上一直头疼,今天脑子炸了。。。炸了一下午。。
简直要死啊。。
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int sg[205];//sg[i]表示连续的i个空格子组成的棋盘的SG值
int vis[205];
char str[205];
int jinqu[205];
int len;
int pos[205];
int pos_cnt;
int vec[205];
int cnt;
void get_sg() {
sg[0] = 0;
sg[1] = 1;
sg[2] = 1;
sg[3] = 1;
sg[4] = 2;
sg[5] = 2;
sg[6] = 0;
for(int i = 7; i <= 205; i ++) {
memset(vis, 0, sizeof(vis));
vis[sg[i - 3]] = 1;
vis[sg[i - 4]] = 1;
vis[sg[i - 5]] = 1;
for(int j = 6; j <= i; j ++) {
vis[(sg[i - j] ^ sg[j - 5])] = 1;
}
for(int j = 0; ; j ++) {
if(!vis[j]) {
sg[i] = j;
break;
}
}
}
}
int get_SG() {
int cnt = 0;
int f = 0;
for(int i = 0; i < len; i ++) {
if(!jinqu[i]) {
f ++;
if(i == len - 1) {
vec[cnt ++] = f;
}
}
else if(jinqu[i] && f != 0){
vec[cnt ++] = f;
f = 0;
}
}
int SG = 0;
for(int i = 0; i < cnt; i ++) {
SG ^= sg[vec[i]];
}
return SG;
}
int main() {
get_sg();
int T;
scanf("%d", &T);
while(T --) {
scanf("%s", str);
len = strlen(str);
int flag = 0;
pos_cnt = 0;
for(int i = 0; i < len; i ++) {
if(i < len - 2 && str[i + 1] == 'X' && str[i + 2] == 'X') {
flag = 1;
pos[pos_cnt ++] = i;
}
else if(i >= 2 && str[i - 1] == 'X' && str[i - 2] == 'X') {
flag = 1;
pos[pos_cnt ++] = i;
}
else if(i >= 1 && str[i - 1] == 'X' && str[i + 1] == 'X') {
flag = 1;
pos[pos_cnt ++] = i;
}
}
if(flag == 1) {
printf("WINNING\n");
for(int i = 0; i < pos_cnt - 1; i ++) {
printf("%d ", pos[i] + 1);
}
printf("%d\n", pos[pos_cnt - 1] + 1);
continue;
}
memset(jinqu, 0, sizeof(jinqu));
for(int i = 0; i < len; i ++) {
if(str[i] == 'X') {
if(i - 2 >= 0) jinqu[i - 2] ++;
if(i - 1 >= 0) jinqu[i - 1] ++;
jinqu[i] ++;
if(i + 1 < len) jinqu[i + 1] ++;
if(i + 2 < len) jinqu[i + 2] ++;
}
}
int SG = get_SG();
//cout << SG << endl;
if(SG == 0) {
printf("LOSING\n\n");
}
else {
printf("WINNING\n");
int ans[205];
int ans_cnt = 0;
for(int i = 0; i < len ; i++) {
if(!jinqu[i]) {
if(i - 2 >= 0) jinqu[i - 2] ++;
if(i - 1 >= 0) jinqu[i - 1] ++;
jinqu[i] ++;
if(i + 1 < len) jinqu[i + 1] ++;
if(i + 2 < len) jinqu[i + 2] ++;
int tmp = get_SG();
//cout << tmp << " ";
if(tmp == 0) {
ans[ans_cnt ++] = i + 1;
//cout << "dui" << endl;
}
if(i - 2 >= 0) jinqu[i - 2] --;
if(i - 1 >= 0) jinqu[i - 1] --;
jinqu[i] --;
if(i + 1 < len) jinqu[i + 1] --;
if(i + 2 < len) jinqu[i + 2] --;
}
}
//cout << endl;
for(int i = 0; i < ans_cnt - 1; i ++) {
printf("%d ", ans[i]);
}
printf("%d\n", ans[ans_cnt - 1]);
}
}
return 0;
}
题目传送:悼念512汶川大地震遇难同胞——选拔志愿者
简单的威佐夫博奕
当n%(m+1) == 0 时为必败状态
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int n, m;
int main() {
int C;
scanf("%d", &C);
while(C --) {
scanf("%d %d", &n, &m);
if(m >= n) {
printf("Grass\n");
}
if(n % (m + 1) == 0) {
printf("Rabbit\n");
}
else printf("Grass\n");
}
return 0;
}
题目传送:Public Sale
也是威佐夫博奕,只不过要输出必胜走法
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int n, m;
int main() {
while(scanf("%d %d", &n, &m) != EOF) {
if(m >= n) {
for(int i = n; i < m; i ++) {
printf("%d ", i);
}
printf("%d\n", m);
}
else {
if(n % (m + 1) == 0) {
printf("none\n");
}
else {
printf("%d\n", n % (m + 1));
}
}
}
return 0;
}
题目传送:Being a Good Boy in Spring Festival
简单Nim博弈,输出可行次数
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int a[105];
int n, m;
int main() {
while(scanf("%d", &m) != EOF) {
if(m == 0) break;
int xor_sum = 0;
for(int i = 0; i < m; i ++) {
scanf("%d", &a[i]);
xor_sum ^= a[i];
}
if(xor_sum == 0) {
printf("0\n");
continue;
}
int ans = 0;
for(int i = 0; i < m; i ++) {
if(a[i] > (xor_sum^a[i])) { //为了使得下一个状态的sg为0,即必败状态,只需要当前第i个数减去若干数以后可以达到其他数的异或和即可,因为这样减去之后此时的sg值为0
ans ++;
}
}
printf("%d\n", ans);
}
return 0;
}
题目传送:取(m堆)石子游戏
和上题类似,也是Nim博弈,只不过输出选择的那个罢了
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int m;
int a[200005];
int main() {
while(scanf("%d", &m) != EOF) {
if(m == 0) break;
int xor_sum = 0;
for(int i = 0; i < m; i ++) {
scanf("%d", &a[i]);
xor_sum ^= a[i];
}
if(xor_sum == 0) {
printf("No\n");
continue;
}
printf("Yes\n");
for(int i = 0 ; i < m; i ++) {
if(a[i] > (xor_sum^a[i])) {
printf("%d %d\n", a[i], xor_sum^a[i]);
}
}
}
return 0;
}
2015-10-4 更新
啊啊啊啊啊啊。
无聊的国庆节啊,在实验室无聊好久了,刷个水题。。。
这个题可以直接根据sg函数找规律即可,规律为2^x-1的时候输出Bob,否则输出Alice。
而sg函数为sg[n] = mex{sg[n-1], sg[n-2], ……,sg[n/2 +1]}。如果n为偶数要集合里要加上sg[n/2]。
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int sg[1005];
int vis[1005];
int n;
set<int> s;
void test() {//通过sg函数找规律
sg[1] = 0;
sg[2] = 1;
for(int i = 3; i <= 80; i ++) {
memset(vis, 0, sizeof(vis));
int k;
if(i & 1) k = i / 2 + 1;
else k = i / 2;
for(; k < i; k ++) {
vis[sg[k]] = 1;
}
for(int j = 0; j < 1005; j ++) {
if(!vis[j]) {
sg[i] = j;
break;
}
}
}
//for(int i = 1; i <= 80; i ++) cout << sg[i] << " "; cout << endl;
for(int i = 1; i <= 80; i ++) if(sg[i] == 0) cout << i << " "; cout << endl;
}
void init() {
int jishu = 1;
for(int i = 1; i <= 30; i ++) {
jishu *= 2;
//cout << jishu - 1 << endl;
s.insert(jishu - 1);
}
}
int main() {
init();
while(scanf("%d", &n) != EOF) {
if(n == 0) break;
if(s.find(n) != s.end()) printf("Bob\n");
else printf("Alice\n");
}
return 0;
}
题目传送:UVA - 11892 - ENimEN
分类:逻辑推理
纸上模拟几下可以发现一个规律:
当然,规律1很好理解。
对于规律2,因为此时的状态都可以转化为1的个数为偶数的后继状态。
比如n为5,a={1,1,5,5,5}。先对其中两个5取走4个,再在第三个5中全部取走就变成两个1了,即1的个数为偶数的后继状态,此时先手(初始时的后手)必败。
在比如n为5,a={1,1,1,5,5}。对其中两个5取走4个,先手再取走一个1,则此时也变为1的个数为偶数的后继状态了,此时先手(初始时的后手)必败。
综上,此时原先手必胜。
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int n;
int main() {
int T;
scanf("%d", &T);
while(T --) {
scanf("%d", &n);
int cnt1 = 0;//用于统计1的个数
int flag = 0;//用于判断是否有除了1以外的数
for(int i = 0; i < n; i ++) {
int t;
scanf("%d", &t);
if(t == 1) cnt1 ++;
else flag = 1;
}
if(flag == 1 || cnt1 & 1) printf("poopi\n");
else printf("piloop\n");
}
return 0;
}
题目传送:UVALive - 3668 - A Funny Stone Game
分析:
一个很经典的博弈题目。关键看怎么分解为子游戏。
这里因为每一堆石子相互之间可能是有影响的,所以不能直接拆分为子游戏。
但是,换个方式思考,就会发现,可以把每一个石子当成一个子游戏。
即可以把位置为i的石子看成一堆个数为n-1-i的石子堆。
所以每一次操作,都会把一堆石子拆分为两个规模更小的石子堆。
比如说,n=3,数组a={1, 2, 3}。此时相当于1堆含有2个石子的石子堆,2堆含有1个石子的石子堆,3个含有0个石子的石子堆(即最后一个数)。
此时选择i=1,j=2,k=3。则等价于将一堆含有2个石子的石子堆->一堆含有1个石子的石子堆,和一堆含有0个石子的石子堆。
好了,总上所述,只要求出23以内的sg函数即可,sg函数可以递推求得,然后暴力找最小字典序解。
AC代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <functional>
#define LL long long
#define INF 0x7fffffff
using namespace std;
int n;
int sg[50];
int vis[305];
void get_sg() {
for(int i = 0; i <= 23; i ++) {
memset(vis, 0, sizeof(vis));
for(int j = i - 1; j >= 0; j --) {
for(int k = j; k >= 0; k --) {
vis[sg[j] ^ sg[k]] = 1;
}
}
for(int j = 0; ; j ++) {
if(!vis[j]) {
sg[i] = j;
break;
}
}
}
}
int a[50];
int ans;
void get_ans() {
for(int i = 0; i < n; i ++) {
if(a[i] == 0) continue;//这里输出的时候,需要特判一下刚开始是否有石子,坑了劳资我好久。。
for(int j = i + 1; j < n; j ++) {
for(int k = j; k < n; k ++) {
if((sg[n - 1 - i] ^ sg[n - 1 - j] ^ sg[n - 1 - k] ^ ans) == 0) {
printf("%d %d %d\n", i, j, k);
return;
}
}
}
}
}
int main() {
get_sg();
//for(int i = 0; i < 23; i ++) cout << sg[i] << " "; cout << endl;
int cas = 1;
while(scanf("%d", &n) != EOF) {
if(n == 0) break;
for(int i = 0; i < n; i ++) {
scanf("%d", &a[i]);
}
ans = 0;
for(int i = 0; i < n; i ++) {
ans ^= (sg[n - 1 - i] * (a[i] & 1));
}
printf("Game %d: ", cas ++);
if(ans == 0) {
printf("-1 -1 -1\n");
}
else {
get_ans();
}
}
return 0;
}