轻松周赛赛题:能否被8整除
题目详情:
给定一个非负整数,问能否重排它的全部数字,使得重排后的数能被8整除。
输入格式:
多组数据,每组数据是一个非负整数。非负整数的位数不超过10000位。
输出格式
每组数据输出一行,YES或者NO,表示能否重排它的全部数字得到能被8整除的数。注意: 重排可以让0开头。
答题说明:
输入样例
610
122
输出样例
YES
NO
解释
第一个数可以变为016 , 160
解析:这是周五下午五点公布的题目,这道题看起来有些难度,全排列、又是不超过10000位,估计看到题都吓尿了,其实正是这两点信息让我们去放弃求全排列,因为即使是不超过10000位的数的全排列的种类都多的已经无法计算如果对每一个数来判断是否能被8整除,那必然是TLE(超时)的。所以我们解决这道题的焦点应该转换到"是否能被8整除",如果大家对数字或者做过类似的题的同学就会知道被0-9任意一个数字整除的数都是有规律的。
这篇博客中有能被0-9所有数字整除的结论,有兴趣的话可以看下(http://blog.csdn.net/lyg105504/article/details/5495080)
在这直接放下"被8整除的数"的结论
当n为一位数时,肯定是8、0
当n为二位数时,应该是16、24、32、40、48、56、64、72、80、88、96
当n为三位数及以上时,该数的末尾(最后)三位数如果能被8整除,则该数就能被8整除
也可能有人不信,其实证明起来也很简单,如下所示(证明)
任何一个三位及其以上的数n都可以进行如下的表示
n=1000*a+100*b+10*c+d (a可以为多位数,b,c,d为0-9的数字)
又因为1000能被8整除则1000*a也可以被8整除,所以该数n是否能被8整除就取决于了后面的的三位数,也就是
n/8=(1000*a)/8+(100*b+10*c+d)/8
也就是(100*b+10*c+d)/8
有了以上的结论,下面需要的是对输入的这个不超过10000位的非负整数进行处理
首先,用什么去输入,如果用整数的话显然位数是达不到的,故而用字符串进行输入,用str变量标记
再者,对字符串进行处理,因为我们只需考虑这个重排数的最后三位,也就是我们只需考虑这个str字符串中出现了0-9中哪几个数字并且是否出现的次数超过三次还是少于三次,如果超过三次,我们只需记录三次而已,因此我们需要定义一个能容纳30个元素的数组,用 int a[30]来表示,举个例子
比如str=11927289799,不管这个str怎么重新排列,我们只需考虑最后三位出现的数字,1出现了2次,2出现了2次,7出现了2次,8出现了1次,9出现了4次,那么这些数字都可能出现在末尾的三位,但是因为9出现了4次,重排后末尾的三位最多能存放3个9,所以我们只需想a数组中存放三个9即可。
最后,我们得到了对字符串处理后的a数组,下面就是对这个数组进行三次遍历,因为重排后0可以开头,所以不需考虑0的问题,但是需要考虑重复的问题,比如数组a[0]已经放在的末尾三位中的其中一位,则a[0]则不能再用,三重循环遍历得到多组a[i],a[j],a[j],组成三位数a[i]*100+a[j]*10+a[k],然后判断是否能被8整除就可以了,如果遍历完成所有的的组合都不能被8整除,则要输出NO,如果一旦有组合能被8整除则输出YES,并同时终止这三重循环(用标记的方法来终止循环)
下面贴下自己写的代码
//是否能被8整除
#include<iostream>
#include<string>
using namespace std;
int main()
{
#ifdef LOCAL
freopen("input.txt" , "r" , stdin);
#endif
string str;
while(cin >> str)
{
//定义存放str字符串中0-9每个数字出现的次数,初始全设置为0
int cnt[10]={0} , m=0 , a[30];
int length= str.length();
for(int i=0; i<length; ++i)
{
if(cnt[str[i]-'0']<3)
{
a[m++]=str[i]-'0';
cnt[str[i]-'0']++;
}
}
//判断是否能被8整除的条件
if(m==1)
{
if(a[m-1]%8==0)
cout << "YES" << endl;
else
cout << "NO" << endl;
}else if(m==2){
if((a[m-1]*10+a[m-2])%8==0 || (a[m-2]*10+a[m-1])%8==0)
cout << "YES" << endl;
else
cout << "NO" << endl;
}else{
int i , flag1=0 , flag2=0;
for(i=0; i<m; ++i)
{
//判断循环是否终止
if(flag1==1)
break;
for(int j=0; j<m; ++j)
{
//判断循环是否终止
if(flag2==1)
break;
if(j!=i)
{
for(int k=0; k<m; ++k)
{
if(k!=i && k!=j)
{
//cout << a[i] << a[j] << a[k] << endl;
if((a[i]*100+a[j]*10+a[k])%8==0)
{
cout << "YES" << endl;
flag1=1;
flag2=1;
break;
}
}
}
}
}
}
if(flag1==0&&flag2==0)
cout << "NO" << endl;
}
}
return 0;
}