多校热身赛之Game HDU - 6944(博弈)

Alice and Bob are playing a game. They take turns and Alice moves first. There is a set of positive integers. In one’s turn, he or she can choose a number (suppose x) in the set, and choose a positive integer k (k does not need to be in the set), and replace x with x−(10^k−1). For example, you can make a number x in the set become x−9 or x−99 or x−999 or x−999⋯. After that the set must still be a set of positive integers. That is to say:

  • The number must still be positive: x−(10^k−1)>0.
  • A set can not have duplicate elements: x−(10^k−1) can not be equal to any other numbers in the set.

They take turns and Alice moves first. The one who can’t move loses the game. Now the question is that who will win the game if they play optimally.
Input
There are multiple test cases.

For each test case, the first line contains a number N, denoting the number of numbers in the set.

The second line contains N different positive integers A1,A2,…,AN, denoting the numbers in the set.

It’s guaranteed that 1≤Ai≤109, and the sum of N of all test cases is not larger than 2⋅10^5.

Output
For each test case, print A for Alice or B for Bob in one line, denoting the winner.

Sample Input
3
1 2 3
3
2 11 20
3
11 12 13
3
10 19 28
2
100 1000

Sample Output
B
B
A
A
A

题意:

给你n个数,每次可以从这些数中选出一个数对其进行减(10^k−1)的操作,k为任意数(正整数),Alice和Bob轮流操作,Alice先开始,不能对这些数进行操作的人就是输者

要求1:数字必须是正的:x−(10k−1)>0。

要求2:一个集合不能有重复的元素:x−(10k−1)不能等于集合中的任何其他数字。

求符合以上条件下谁是胜者

思路:

首先分析x−(10k−1),减的这个数只能是9,99,999,…

99=9 * 11
999=9 * 111
999…=9 * K

这些数都是9的倍数,K是个奇数,所以对结果没有影响,因此我们可以将这个问题转化为每次减9

将这些数从小到大排序,每次先从最小的开始减

例如:19 10 29 不排序从第一个开始减最后减到的最小结果就是19 10 11(因为19-9=10,与第二个数字10有重复)
排序后的最小结果是1 10 11,这个在计算过程中不会出现少操作数,每个人都可以做到最佳选择

因为存在最后减完的结果一样,但是题目要求不可以出现重复的数字,所以需要再次处理
每次从最小的开始减,余数不为0的每次就让第一个减到0*9+余数,第二个减到1 * 9+余数…以此类推(如果余数为0,第一个减到1 * 9,第二个减到2 * 9,以此类推)

这里的避重(避免重复)操作数可以用前n项和实现
(余数为0) 例:9 18 27 化为最小结果(未对余数进行避重)分别需要的操作是 1 2 3次,总操作数=6
避重的话9应该减为1 * 9,18减为2 * 9,27减为3 * 9,需要的总操作数是1+2+3=6次
6-6=0,所以最后只能对这组数据进行0次操作。
(余数不为0),与上类似,只是第一个数减到0 * 9+余数…

最后总结我们需要计算的就是:

一、将每个数化到最小一共需要多少次操作(一共能减多少次9,先不考虑余数相同)
二、统计余数相同的个数(对9取余 余数为0到8)
三、余数相同的数字,计算去重操作数
四、总操作数-避重操作数即为最后的操作数,如果为偶数,则B赢,反之,则A赢。

代码:

#include<bits/stdc++.h>
using namespace std;
int a[200010],b[200010],c[200010],book[10];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(book,0,sizeof(book));
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        for(int i=1; i<=n; i++)
        {
            b[i]=a[i]/9;//计算化到最小所需的操作数
            c[i]=a[i]%9;//余数
        }
        int ans=0;
        for(int i=1; i<=n; i++)
            ans+=b[i];
        for(int i=1; i<=n; i++)
            book[c[i]]++;//对余数进行计数
        int k;
        for(int i=1; i<=8; i++)
        {
            k=0;
            if(i==0)//余数为0
                k=(book[i]*(book[i]+1))/2;
            else//余数不为0
                k=(book[i]*(book[i]-1))/2;
            ans=ans-k;//总操作数-避重操作数即为最终所需操作数
        }
        if(ans%2)
            printf("A\n");
        else
            printf("B\n");
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值