题目相关
题目链接
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
through9
.
题解报告
题目翻译
给一个有数字 1 到 9 构成的字符串,判断能否通过交换位置,使得这个字符串对应的数字可以被 8 整除。
题目分析
看到这个题目,第一反应是全排序,也就是根据提供的字符串列出全排列,然后再验证是否能被 8 整除。例如字符串为 1234,我们可以通过 STL 的 next_permutation() 函数实现。这样我们写道 1432 的时候,这个数字可以被 8 整除。
但是看到数据长度 2×10^5 的时候,就知道这个方法是不可行的。
仔细思考后,又是一个数学题。这题的核心数学是如何判断一个数字能被 8 整除。
判断数字能否被 8 整除
通过数学归纳法,我们可以发现。由于本题没有数字 0。
- 数据长度为 1 的时候,8 可以被 8 整除。
- 数据长度为 2 的时候,16、24、32、40、48、56、64、72、80、88、96,这些数字可以被 8 整除。
- 数据长度大于 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),有点不是很确定。惭愧。