欧拉计划43题

Sub-string divisibility

The number, 1406357289, is a 0 to 9 pandigital number because it is made up of each of the digits 0 to 9 in some order, but it also has a rather interesting sub-string divisibility property.

Let d1 be the 1st digit, d2 be the 2nd digit, and so on. In this way, we note the following:

  • d_2d_3d_4=406 is divisible by 2
  • d_3d_4d_5=063 is divisible by 3
  • d_4d_5d_6=635 is divisible by 5
  • d_5d_6d_7=357 is divisible by 7
  • d_6d_7d_8=572 is divisible by 11
  • d_7d_8d_9=728 is divisible by 13
  • d_8d_9d_{10}=289 is divisible by 17

Find the sum of all 0 to 9 pandigital numbers with this property.

1406357289是一个0至9全数字数,因为它由0到9这十个数字排列而成;但除此之外,它还有一个有趣的性质:子串的可整除性。

记d1是它的第1个数字,d2是第2个数字,依此类推,注意到:

  • d_2d_3d_4=406能被2整除
  • d_3d_4d_5=063能被3整除
  • d_4d_5d_6=635能被5整除
  • d_5d_6d_7=357能被7整除
  • d_6d_7d_8=572能被11整除
  • d_7d_8d_9=728能被13整除
  • d_8d_9d_{10}=289能被17整除

找出所有满足同样性质的0至9全数字数,并求它们的和。

         这个题目要求,满足0-9全数组的数,并且每3位会满足题目条件的数的和,那么进行分析;

        1.如何求0-9全数字

        2.求到全数字怎么去进行,对没3位的题目条件进行判断;

        进行对第一点分析,找10个位置,第一个位置放了一个数,那么这个数就在后面不能用了,所以需要记录这个位置放了的数,后面依次进行这样的操作;到最后一个位置填完最后一个数时,进行回溯,回溯到第二位置,进行填之前没有填过的数,一直回溯加递归加循环的一个过程,就可以求到,0-9全数字的全排列;

        对第二点分析,可以在第一点求得的情况下,讲数字进行每位存储在数组中,那么就可以很好的找到每位的数组进行来判断了;

        下面是代码实现的过程:

        

#include 
#include 
#include 
#define MAX_N 5000000

int num[10] = {0};//用来记录每位数字是否被用过
char buff[15] = {0};//用来排列
int sum[MAX_N + 5][15];//用来存满足题目含0-9数字的10位数的数值,
int s = 0;

void get_int(char *buff) {//讲字符串换位数组中
    sum[0][0]++;
    for (int i = 0; buff[i]; i++) {
        sum[sum[0][0]][i] = buff[i] - '0';
    }
    return ;
}

void get_num(int n, int k, char *buff) {//获取0-9的全排列
    if (k == 10) {//当k==10说明以及有10位了,所以进行转换
        if (buff[0] == '0') return ;//第一位为0不满住题目条件所以不记录
        get_int(buff);
        return ;
    }
    for (int i = n; i < 10; i++) {
        while (num[s]) {//来确定当前数是否被用过
            s++;
            if (s == 10) s = 0;
        }
        buff[k] = s + '0';//将这个数赋进字符串
        num[s] = 1;//现在标记这个数被用
        get_num(n + 1, k + 1, buff);//开始对下个位置进行赋值
        num[buff[k] - '0'] = 0;//回溯当前位置的数字未被用过,因为s一直都在变化,所以这里不能用s进行回溯只能用当前位置的数字来进行回溯
    }
    return ;
}

long long is_interesting_num(int *a) {
    int fact[7] = {2, 3, 5, 7, 11, 13, 17}, j = 0;//题目条件的被除数
    int g = a[0];//第一位直接赋值,只要不为0就可以,在上面的函数中已经剔除掉第一位为0的情况
    long long return_num = a[0];//如果满足条件,进行返回的值
    for (int i = 1; i < 10; i++) {
        g = g * 10 + a[i];
        return_num = return_num * 10 + a[i];
        if (i < 3) continue;//当i<3时,还不足3位
        g -= a[i - 3] * 1000;//假如当前是第4位,就需要减去第一位来进行判断下面一步操作
        if (g % fact[j++]) return 0;
    }
    return return_num;
}

void output(int *a) {
    for (int i = 0; i < 10; i++) {
        printf("%d", a[i]);
    }
    putchar(10);
    return ;
}

int main() {
    get_num(0, 0, buff); 
    long long ans = 0;
    for (int i = 1; i <= sum[0][0]; i++) {
        long long g = is_interesting_num(sum[i]);
        if (!g) continue;
        ans += g; 
    }
    printf("%lld\n", ans);
    return 0;
}

最终答案: 16695334890

 

你可能感兴趣的:(算法)