AtCoder题解—— AtCoder Beginner Contest 181 —— D - Hachi

题目相关

题目链接

AtCoder Beginner Contest 181 D 题,https://atcoder.jp/contests/abc181/tasks/abc181_d

Problem Statement

Given is a digit sequence S consisting of the digits from 1 through 9.

Takahashi, the bee, loves multiples of 8. He is trying to make a multiple of 8 by permuting the digit sequence S.

Determine whether it is possible.

Input

Input is given from Standard Input in the following format:

S

Output

If it is possible to make a multiple of 8 by permuting the digit sequence S, print Yes; otherwise, print No.

Samples1

Sample Input 1

1234

Sample Output 1

Yes

Explaination

For example, permuting 1234 into 1432 results in a multiple of 8.

Samples2

Sample Input 2

1333

Sample Output 2

No

Explaination

There is no way to permute 1333 into a multiple of 8.

Samples3

Sample Input 3

8

Sample Output 3

Yes

Constraints

  • 1≤|S|≤2×10^5
  • Each character of S is one of the digits from 1 through 9.

题解报告

题目翻译

给一个有数字 1 到 9 构成的字符串,判断能否通过交换位置,使得这个字符串对应的数字可以被 8 整除。

题目分析

看到这个题目,第一反应是全排序,也就是根据提供的字符串列出全排列,然后再验证是否能被 8 整除。例如字符串为 1234,我们可以通过 STL 的 next_permutation() 函数实现。这样我们写道 1432 的时候,这个数字可以被 8 整除。

但是看到数据长度 2×10^5 的时候,就知道这个方法是不可行的。

仔细思考后,又是一个数学题。这题的核心数学是如何判断一个数字能被 8 整除。

判断数字能否被 8 整除

通过数学归纳法,我们可以发现。由于本题没有数字 0。

  1. 数据长度为 1 的时候,8 可以被 8 整除。
  2. 数据长度为 2 的时候,16、24、32、40、48、56、64、72、80、88、96,这些数字可以被 8 整除。
  3. 数据长度大于 2 的时候,末尾 3 位为 104、112、...、984、992,这些数字能被 8 整除。

这样我们就找到了规律。

结论

本题就是统计是否有这样的规律,而不需要去构造字符串。如何使用这样规律呢?

数据长度为 1 和 2,只需要特判就可以了。

数据长度超过 2 的,将对应的字符串每位数字的个数统计出来。使用如下的伪码:

for (int i=104; i<1000; i++) {
    统计数字 i 变为有几个 1 ~ 9 构成。将结果保存在数组 tmp[10] 中
    比对 tmp 和 num 数组
    只要 tmp 数组中的任意一个数据大于 num 数组,说明不能构成
    tmp 数组中所有数据都小于等于 num 数组,说明可以构成
}

例如我们输入 98433333333333333333333333333333333333333666666。我们统计每个数字出现的个数,即统计数字 1 ~ 9 出现的个数。这样我们可以得到下面的数组:

num[0]=0;
num[1]=0;
num[2]=0;
num[3]=38;
num[4]=1;
num[5]=0;
num[6]=6;
num[7]=0;
num[8]=1;
num[9]=1;

然后判断这些数字能否组合成为 104、112、...、984、992 这样的数字。当我们遍历到 336 的时候,也就是说末尾三个数字变成 336,就可以被 8 整除。

例如我们输入 1333。我们统计每个数字出现的个数,即统计数字 1 ~ 9 出现的个数。这样我们可以得到下面的数组:

num[0]=0;
num[1]=1;
num[2]=0;
num[3]=3;
num[4]=0;
num[5]=0;
num[6]=0;
num[7]=0;
num[8]=0;
num[9]=0;

然后判断这些数字能否组合成为 104、112、...、984、992 这样的数字。整个遍历完成后,发现没有办法构成被 8 整除的数据。

例如 104 对应的统计数据如下:

num[0]=1;
num[1]=1;
num[2]=0;
num[3]=0;
num[4]=1;
num[5]=0;
num[6]=0;
num[7]=0;
num[8]=0;
num[9]=0;

其中 tmp[0]>num[0],说明没法构成 104。其他数据以此类推。

AC 参考代码

//https://atcoder.jp/contests/abc181/tasks/abc181_d
//D - Hachi
#include <bits/stdc++.h>

using namespace std;

string str;//保存字符串
int num[10];//数字0~9

bool judge(int x) {
    int t=x;
    int tmp[10]={};
    while (t) {
        tmp[t%10]++;
        t/=10;
    }
    for (int i=0; i<10; i++) {
        if (tmp[i]>num[i]) {
            return false;
        }
    }
    return true;
}

int main() {
    cin>>str;

    int len=str.length();
    for (int i=0; i<len; i++) {
        num[str[i]-'0']++;
    }

    if (1==len) {
        //长度是 1
        if ("8"==str) {
            cout<<"Yes\n";
        } else {
            cout<<"No\n";
        }
        return 0;
    } else if (2==len) {
        //长度是 2
        int n = stoi(str);
        if (0==n%8) {
            cout<<"Yes\n";
            return 0;
        }
        n = n/10+n%10*10;
        if (0==n%8) {
            cout<<"Yes\n";
        } else {
            cout<<"No\n";
        }
        return 0;
    }
    //判断
    for (int i=104; i<1000; i+=8) {
        if (judge(i)) {
            cout<<"Yes\n";
            return 0;
        }
    }
    cout<<"No\n";

    return 0;
}

时间复杂度

应该是 O(N),有点不是很确定。惭愧。

AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道的简要题解: A - Dodecagon 目描述:已知一个正十二边形的边长,求它的面积。 解思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值