首页 > 其他分享 >Even Number Addicts - 题解【动态规划/记忆化搜索】

Even Number Addicts - 题解【动态规划/记忆化搜索】

时间:2022-10-01 02:22:04浏览次数:84  
标签:Even ac en int 题解 Number Alice Bob dp

题面

本题是Codeforces Global Round 22 的C题。原题链接见:C. Even Number Addicts。下面搬运一下题面:

Description

Alice and Bob are playing a game on a sequence \(a_1,a_2,…,a_n\) of length \(n\). They move in turns and Alice moves first.

In the turn of each player, he or she should select an integer and remove it from the sequence. The game ends when there is no integer left in the sequence.

Alice wins if the sum of her selected integers is even; otherwise, Bob wins.

Your task is to determine who will win the game, if both players play optimally.

Input

Each test contains multiple test cases. The first line contains an integer \(t (1≤t≤100)\) — the number of test cases. The following lines contain the description of each test case.

The first line of each test case contains an integer \(n\) \((1≤n≤100)\), indicating the length of the sequence.

The second line of each test case contains \(n\) integers \(a_1,a_2,…,a_n\) \((−10^9 ≤ a_i ≤ 10^9)\), indicating the elements of the sequence.

Output

For each test case, output "Alice" (without quotes) if Alice wins and "Bob" (without quotes) otherwise.

Example

input

4
3
1 3 5
4
1 3 5 7
4
1 2 3 4
4
10 20 30 40

output

Alice
Alice
Bob
Alice

Note

In the first and second test cases, Alice always selects two odd numbers, so the sum of her selected numbers is always even. Therefore, Alice always wins.

In the third test case, Bob has a winning strategy that he always selects a number with the same parity as Alice selects in her last turn. Therefore, Bob always wins.

In the fourth test case, Alice always selects two even numbers, so the sum of her selected numbers is always even. Therefore, Alice always wins.

大意

给定一组数,Alice和Bob轮流取数,直到取完为止,Alice先。若Alice手上的数和为偶数则Alice胜利,否则Bob胜利。假设他们非常聪明,总是选择对自己有利的策略,问该局谁会赢。

题解

一开始以为是个博弈论,后来发现是个动态规划……

首先,对于本题我们不需要关心具体的数是什么,只要关心每个数的奇偶性就行。因此,预先计算出这组数的奇数个数与偶数个数。计奇数个数为on,偶数个数为en,很显然的可以想到以下情况:若全偶数Alice必胜,若全奇数,则Alice能够拿到一半(向上取整)奇数,若拿到的个数为偶数则赢,否则输。

剩下的情况中,在每一轮选取数字中,一共会出现四种情况(用AB代表Alice与Bob,10代表奇偶):00,01,10,11。这样,剩下的奇数和偶数个数又构成了一个子问题。但是,我们发现,根据Alice取的数不同,ta手上的数奇偶性是会改变的。因此,我们定义dp[i][j][k]代表有\(i\)个奇数\(j\)个偶数并且Alice手上数总和奇偶性为\(k\)(1代表奇数0代表偶数)时是否能胜利(1代表能,-1代表不能)。

由于两人都按照最优策略行事,因此在00、01情况中Bob一定会选择对他有利的操作,就是Alice必输的操作。10、11两种情况同理。因此可以得到转移方程

\[dp[i][j][k]=\max(\min(dp[i-1][j-1][1-k],dp[i-2][j][1-k]),\min(dp[i-1][j-1][k],dp[i][j-2][k])) \]

转移方程中,因为\(k\)只取0或1,因此奇偶性变换时只需要计算\(1-k\)就可以了。在Alice取走奇数时,Bob要在取奇数dp[i-2][j][1-k]与取偶数dp[i-1][j-1][1-k]中做出能让Alice输的选择,在前面的定义中赢为1输为-1,所以需要在这两个表达式中取最小值。取走偶数同理。同时Alice想赢,因此需要在取奇数与取偶数的结果中取max。

根据转移方程,可以采用自顶向下记忆化搜索的策略进行求解,使用一个map记录当前状态是否搜索过。因为map初始化为0,因此输赢用1与-1表示。

代码

这里使用了tuple,这是一个和pair很像的东西。

/*
 * @Author: AlexHoring
 * @Date: 2022-09-30 22:59:37
 */
#include <bits/stdc++.h>
#define GRP(a) if(a!=0){int T;cin>>T;for(int C=1;C<=T;++C){solve(C);}}else{solve(0);}
#define FAST ios::sync_with_stdio(false);cin.tie(0);
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,a,b) for(int i=a;i>=b;--i)
#define elif else if
#define mem(arr,val) memset(arr,val,sizeof(arr))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

int n;
vector<int> a;
map<tuple<int, int, int>, int> dp;

int dfs(int on, int en, int ac) {
    if (dp[make_tuple(on, en, ac)] != 0) {
        return dp[make_tuple(on, en, ac)];
    }
    if (on == 0) {
        if (ac != 0) {
            dp[make_tuple(on, en, ac)] = -1;
            return -1;
        } else {
            dp[make_tuple(on, en, ac)] = 1;
            return 1;
        }
    }
    if (en == 0) {
        int num = on / 2 + on % 2;
        if (num % 2 == 0) {
            if (ac != 0) {
                dp[make_tuple(on, en, ac)] = -1;
                return -1;
            } else {
                dp[make_tuple(on, en, ac)] = 1;
                return 1;
            }
        } else {
            if (ac == 0) {
                dp[make_tuple(on, en, ac)] = -1;
                return -1;
            } else {
                dp[make_tuple(on, en, ac)] = 1;
                return 1;
            }
        }
    }
    --on;
    int b = dfs(on, en - 1, 1 - ac);
    if (on != 0) {
        b = min(b, dfs(on - 1, en, 1 - ac));
    }
    int ans = b;
    ++on;
    --en;
    b = dfs(on - 1, en, ac);
    if (en != 0) {
        b = min(b, dfs(on, en - 1, ac));
    }
    ++en;
    ans = max(ans, b);
    dp[make_tuple(on, en, ac)] = ans;
    return ans;
}

void solve(int C) {
    dp.clear();
    cin >> n;
    a.resize(n + 1);
    int on = 0, en = 0;
    rep(i, 1, n) {
        cin >> a[i];
        if (a[i] % 2) {
            ++on;
        } else {
            ++en;
        }
    }
    int ans = dfs(on, en, 0);
    if (ans == 1) {
        cout << "Alice\n";
    } else {
        cout << "Bob\n";
    }
}

int main() {
#ifdef AlexHoring
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
#endif
    FAST;
    GRP(10);
    return 0;
}

/*
          _           _    _            _
    /\   | |         | |  | |          (_)
   /  \  | | _____  _| |__| | ___  _ __ _ _ __   __ _
  / /\ \ | |/ _ \ \/ /  __  |/ _ \| '__| | '_ \ / _` |
 / ____ \| |  __/>  <| |  | | (_) | |  | | | | | (_| |
/_/    \_\_|\___/_/\_\_|  |_|\___/|_|  |_|_| |_|\__, |
                                                 __/ |
                                                |___/
*/

标签:Even,ac,en,int,题解,Number,Alice,Bob,dp
From: https://www.cnblogs.com/AlexHoring/p/16746653.html

相关文章

  • LJT的书库题解
    原题链接题目难度较低,看懂题目后特别好想。注意到题目中说的,一个藏书室最多与两个相同的藏书室相连。那么含有所需书的藏书室是树上的一条链。但是,书的本数未知,且链的两......
  • js event
          ......
  • 【Azure 应用服务】本地Node.js部署上云(Azure App Service for Linux)遇到的三个问题
    问题描述当本地Node.js(Linux+Node.js+npm+yarn)部署上云,选择AzureAppServiceforLinux环境。但是在部署时,遇见了以下三个问题:问题一:使用VSCode进行部署,部署速......
  • CF600C题解
    题意有一串字符串\(S\),设改变\(S\)中的任意一个字符称为1次转变(交换任意2个字符不算转变次数),求在操作最少的情况下可得到的回文字符串正文♦算法:找规律♦准备......
  • 题解 [POI2010]ZAB-Frog
    很厉害的题。倍增和单调队列。这是zpl新手向算法第二弹,第一弹可以看小挖的核燃料填充我会尽量讲的比较细致。同第一弹,尽量配合代码食用。这道题的题目描述写的不是......
  • useState"失效“问题解释和解决方案
    示例:const[count,setCount]=useState(0)简单的onclick事件中,setCount(1)后紧接着输出或者使用,则输出的值还是0原因:setState会导致页面刷新,(useRef不会)页面刷新的时候......
  • 【题解】P2167 [SDOI2009]Bill的挑战(状压 DP)
    【题解】P2167[SDOI2009]Bill的挑战挺好的一道状压DP。可惜我脑子有病。()题目链接P2167[SDOI2009]Bill的挑战](https://www.luogu.com.cn/problem/P3225)题意概述......
  • 13.56M系列芯片-SI522/SI522A/SI523/ FMI7522 /FMI7550 /RC522芯片常见问题解答
    13.56M系列芯片-标配版:SI522/SI522A/SI523的几款芯片会遇到的一些常见问题解答:SI522和SI522A的异同点?SI522A为SI522的升级版本,SI522A增加了ACD工作模式,其他均相同。标配......
  • WPF中Trigger、DataTrigger、EventTrigger区别
    Trigger属性触发器它监视所有者控件上的特定属性,当该属性具有与指定值匹配的值时,属性可以更改。<TriggerProperty="IsMouseOver"Value="True"> DataTrigger数据......
  • LG4381 [IOI2008] Island 题解
    LG4381[IOI2008]Island给定一个基环树森林,求每棵基环树的直径长度和。直径是基环树上最长的一条简单路径。题目保证树边的方向构成了一颗内向树。题解先简单说一下......