題目:給定一個非負整數,問能否重排它的全部數字,使得重排後的數能被8整除。 輸入格式: 多組數據,每組數據是一個非負整數。非負整數的位數不超過10000位。 輸出格式 每組數據輸出一行,YES或者NO,表示能否重排它的全部數字得到能被8整除的數。注意: 重排可以讓0開頭。
思路:
- 考慮到64位整型可以直接取餘8求得結果,所以當輸入非負整數位數小於20位的時候,可以直接轉換成64位整型進行計算。
- 對於一個非負整數,最後四位相當於是 p*1000 + x*100 + y*10 + z ,可以很顯然的看出p*1000必然能被8整除,所以一個非負整數只需要後三位能被8整除,那麼這個數就一定能被8整除。所以如果我們能從這個數中任意取出三位,作爲最後三位,其值能被8整除,就輸出YES,否則NO。
- 沒必要對可能的10000位做全排列,因爲0-9每個數最多隻能用3次,我們只需要遍歷一遍每一位,將0-9出現的次數記錄下來,最多允許記錄3次。這樣最壞的情況下需要對30個數進行全排列即可,效率會非常高。
代碼:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#define MAX 10001
int has_num[10]; //0-9在這個數中出現的次數
bool check()
{
int deal_num[30]; //0-9每個數最多可以用3次,只需要30的空間
int n = 0;
//將所有出現過數依次存放在deal_num數組中
for (int i=0; i<10; i++) {
for (int j=0; j<has_num[i]; j++) {
deal_num[n] = i;
n++;
}
}
//排列任意三個數組成一個整數,其值能被8整除,返回true,否則false
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
if (j == i)
continue;
for (int k=0; k<n; k++) {
if (k == i || k == j) {
continue;
}
if ((deal_num[i]*100 + deal_num[j]*10 + deal_num[k]) % 8 == 0)
return true;
}
}
}
return false;
}
int main()
{
char str_num[MAX]; //用於保存不超過10000位的整數
int n;
long long temp = 0; //如果位數小於等於19,直接轉換爲64位整型
for (;;) {
memset(str_num, 0, sizeof(str_num));
for (int i=0; i<10; i++) {
has_num[i] = 0;
}
if (scanf("%s", &str_num) == 1) {
n = strlen(str_num);
//轉換爲64位整型
if (n <= 19) {
sscanf(str_num, "%lld", &temp);
if ((temp % 8) == 0)
printf("YES\n");
else
printf("NO\n");
continue;
}
//將0-9出現的次數保存在has_num數組中,最多3次
for (int i=0; i<n; i++) {
if (has_num[(int)str_num[i] - 48] < 3)
has_num[(int)str_num[i] - 48]++;
}
if (check())
printf("YES\n");
else
printf("NO\n");
continue;
} else {
break;
}
}
return 0;
}