轻松周赛赛题:是否能被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整除
也可能有人不信。事实上证明起来也非常easy,例如以下所看到的(证明)
不论什么一个三位及其以上的数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; }