幸运数字(蓝桥杯23省赛)

题目分析

暴力判断的思路就不讲了,这道题主要想将一个思想,对于这种数字类的题目,对半枚举的思路。

100000000是不符合要求的,所以最多遍历到99999999。这个思路是我一半一半的凑,把9999999分成两半,每一半的位数最多是9999。这里的i遍历的就是左半边的位数,所以是小于等于4的。

 for (int i = 1; i <= 4; i++) {}

第二层for循环遍历的是左半边各位数字之和,最大就是这i位都为9,那么值就是i*9

 for (int j = 1; j <= i * 9; j++) {

现在我要找右边那一半是多少,按理说左边位数确定了,右边和他一样就行了,不用遍历,但是这样做的话我就找不到类似1001这样的数字了,因为这个数字左半边值是10,右半边值是1,也就是说满足题意的数字,并不要求左右半边相等,不相等,也就是右边比左边位数少的时候,我补0就可以了。1001就是右半边的1补了0。

for (int k = 1; k <= i; k++)

然后我只需要这点位数为i和为j和位数为k和为j的数字的个数,然后让它们相乘即可。

 count += a[i][j] * a[k][j];

提问:但是怎么这个0才会出现呢,就是怎么才能补上?

如果我没有第三层遍历,我只找了和左边位数一样的右边就是没有补0,如果我有第三层遍历,我允许右边位数比左边位数小的情况存在,就是补了。它不是显式的有一个操作我把1的左边加个0,而是我认为10和1能够凑成一个合法数字,说明我把10和1凑一起的时候是1001这样凑的而不是101这样凑。

提问:a[i][j]∗a[k][j]a[i][j]*a[k][j] a[i][j]a[k][j]所以这个就是一个i位和为j的数和一个k位和为j的数相乘对吗?也就比如1322,就是13和22相乘吗或者是1001,是10和1相乘

不是的。举个例子。

a [ 3 ] [ 5 ]a[3][5]a[3][5]代表位数3各位数之和为5的数字个数,比如有122,221,212,203,230,302,320,140,104,410,401,500,113,131,311。所以 a [ 3 ] [ 5 ] = 15a[3][5]=15a[3][5]=15

a [ 2 ] [ 5 ]a[2][5]a[2][5]代表位数2各位数之和为5的数字个数,比如有23,32,50,14,41,所以 a [ 2 ] [ 5 ] = 5a[2][5]=5a[2][5]=5

那么 a [ 3 ] [ 5 ] ∗ a [ 2 ] [ 5 ] = 15 ∗ 5 = 75a[3][5]*a[2][5]=15*5=75a[3][5]a[2][5]=155=75,也就是找到了75个合法数字,他们分别是122023,122032,122050,122014,122041,221023,221032等。

根据上述例子,左半边和右半边的位数不同也没有关系,我在右半边数字的左边添0依然可以组成合法数字。

题目代码

public class Main {static int a[][] = new int[5][50]; // 定义数组a[i][j]表示i位数和为j,j最大为9*i;static int count = 0; static void num(int x) {int t = 0, sum = 0; // t为位数,sum为各个位上的数字之和 while (x>0) { //这个循环主要就是用来求各个位上的数字之和的 sum += x % 10; // 取x的个位数加到sum中x /= 10; // 将x除以10,相当于去掉x的个位数t++; //计数:数字的位数+1 }a[t][sum]++; //和为sum的t位数,这个数的个数+1,数组加 } public static void main(String[] args) {for (int i = 1; i <= 9999; i++) {num(i); //调num函数 } // System.out.println(a[3][5] + " " + a[2][5]);//for (int i = 1; i <= 4; i++) { // 左一半,1~4 for (int j = 1; j <= i * 9; j++) {//一半的和,最大就是这i位都为9,那么值就是i*9for (int k = 1; k <= i; k++) { // 枚举右一半的位数,可以比左半边位数小count += a[i][j] * a[k][j];//}}}System.out.println(count);}}
#include int a[5][50] = {0}; // 定义数组a[i][j]表示i位数和为j,j最大为9*i;int count = 0; void num(int x) {int t = 0, sum = 0; // t为位数,sum为各个位上的数字之和 while (x) { //这个循环主要就是用来求各个位上的数字之和的 sum += x % 10; // 取x的个位数加到sum中x /= 10; // 将x除以10,相当于去掉x的个位数t++; //计数:数字的位数+1 }a[t][sum]++; //和为sum的t位数,这个数的个数+1,数组加 } int main() {for (int i = 1; i <= 9999; i++) {num(i); //调num函数 }//for (int i = 1; i <= 4; i++) { // 左一半,1~4 、for (int j = 1; j <= i * 9; j++) {//一半的和,最大就是这i位都为9,那么值就是i*9for (int k = 1; k <= i; k++) { // 枚举右一半的位数,可以比左半边位数小count += a[i][j] * a[k][j];//}}}printf("%d", count);return 0;}