题意:有 n 堆石子,有两种操作,一种是从一堆中拿走一个,另一种是把两堆合并起来,Alice 先拿,谁不能拿了谁输,问谁胜。
析:某些堆石子数量为 1 是特殊,石子数量大于 1 个的都合并起来,再拿,这是最优的,因为都想另一个输,并且第二种操作是可以翻转胜负的,所以都会先采取第二个操作,但是砘数量为 1 却不是,所以要分开考虑,dp[i][j] 表示,数量为 1 的堆的个数,总的操作数为 j,先手胜还是负。
考虑边界,如果剩下的都是 1 的,那么 i % 3 != 0 先手胜,
如果没有 1了,那么那是 j % 2 != 0 先手胜,
如果 j 只剩下一个了,那么就可以合并到 1,
操作有三种,第一种,从石子为 1 个的堆中拿一个
第二种,从石子不为 1 的堆中拿一个
第三种,把两个堆石子为 1 的进行合并,并放到总操作数中。
代码如下:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <algorithm> #include <vector> #include <map> #include <cctype> #include <cmath> #include <stack> #include <sstream> #include <list> #include <assert.h> #include <bitset> #include <numeric> #define debug() puts("++++") #define gcd(a, b) __gcd(a, b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second #define pb push_back #define sqr(x) ((x)*(x)) #define ms(a,b) memset(a, b, sizeof a) #define sz size() #define be begin() #define ed end() #define pu push_up #define pd push_down #define cl clear() #define lowbit(x) -x&x //#define all 1,n,1 #define FOR(i,n,x) for(int i = (x); i < (n); ++i) #define freopenr freopen("in.in", "r", stdin) #define freopenw freopen("out.out", "w", stdout) using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> P; const int INF = 0x3f3f3f3f; const LL LNF = 1e17; const double inf = 1e20; const double PI = acos(-1.0); const double eps = 1e-8; const int maxn = 1e5 + 10; const int maxm = 1e6 + 10; const LL mod = 1000000007; const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1}; const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1}; const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; int n, m; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; inline bool is_in(int r, int c) { return r >= 0 && r < n && c >= 0 && c < m; } inline int readInt(){ int x; scanf("%d", &x); return x; } int dp[55][1000 * 50+100]; bool dfs(int n, int m){ int &ans = dp[n][m]; if(ans >= 0) return ans; if(n == 0) return ans = m&1; if(m == 0) return ans = (n % 3 != 0); if(m == 1) return ans = dfs(n+1, 0); if(!dfs(n-1, m)) return ans = 1; if(!dfs(n, m-1)) return ans = 1; if(!dfs(n-1, m+1)) return ans = 1; if(n > 1 & !dfs(n-2, m + 3)) return ans = 1; return ans = 0; } int main(){ ms(dp, -1); int T; cin >> T; for(int kase = 1; kase <= T; ++kase){ scanf("%d", &n); int cnt1 = 0, sum = 0; for(int i = 1; i <= n; ++i){ int x = readInt(); if(x == 1) ++cnt1; else sum += x; } sum += max(0, n - cnt1 - 1); printf("Case #%d: %s ", kase, dfs(cnt1, sum) ? "Alice" : "Bob"); } return 0; }