题目描述:
-
亲们!!我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他。问题是:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数
-
输入:
-
输入有多组数据,每组测试数据为一行。
每一行有两个整数a,b(0<=a,b<=1,000,000,000)。
-
输出:
-
对应每个测试案例,输出a和b之间1出现的次数。
0 5 1 13 21 55 31 99
1 6 4 7
解题思路:
这道题目要注意几个问题:
第一个,比如10 到15 出现几个1?是7个...数字10 12 13 14 15各出现一次,11出现两次,因此是7次。
第二个,输入的两个数,第一个数,可能比第二个大。因此如果第一个数大于第二个数要进行一次调整。
if(n>m)
swap(&n,&m);
第三个,就是这道题的主要思想。
主要思想,通过递归来求解。我们分别求出两个数含有1的个数,但是要注意,对小的的数求解时,要减1.因为如果是10到15,0到10应该含有2个1,而0到15含有8个1,如果直接相减,10的那个1就被减掉了。因此要减1求解。
char numN[MAXSIZE]; char numM[MAXSIZE]; sprintf(numN,"%d",n-1); sprintf(numM,"%d",m); numberOfN = getNumber(numN); numberOfM = getNumber(numM); printf("%d\n",numberOfM-numberOfN);
算法主要思想,首先我们看最高位。把数分解,abcde就分解成 1到bcde与bcde+1到abcde 两段。比如,34567分解成1到4567,与,4568到34567.这样求解第2段,只需要考虑第一位,和后面几位的普通情况就行了。然后递归求第1段。
最高位case1:如果最高位是大于1的数。那么就分包含1的情况,和1以外的情况。应该就是后面的个个位数为1其他位随机的数目。即,first*(length-1)*power(length-2),后面的(length-1)位为1,剩余(length-2)位0到9随机共10种。即在本例中为2*4*1000种,即11000,11001,11002,11003...21000,21002,21003,21004...即每一位为1*其他几位的随机数。此处就是4*1000.
最高位case2:对于最高位是1的,后面无论是什么都满足情况。因此,如果高位刚好等于1,那么满足的情况更应该是后面的数字之和。
举个例子,
numF = 0;
if(firstNum > 1) numF = power(length-1);//如22345,最高位大于1时,满足的情况为10000-19999,即10000种. elseif(firstNum == 1) numF = atoi(num+1)+1;//如12345,最高位为等于1时,满足的情况为2345种(不考虑后面的).
int getNumber(const char *num){ int firstNum = *num-'0';//字符转数字 int length = strlen(num); int numF,numOther,numL; if(!num || *num < '0' || *num > '9' || *num == '\0')l return0; if(length == 1 && firstNum == 0) return0; if(length == 1 && firstNum > 0) return1; numF = 0; if(firstNum > 1) numF = power(length-1); elseif(firstNum == 1) numF = atoi(num+1)+1; numOther = firstNum*(length-1)*power(length-2); numL = getNumber(num+1);//递归调getNumber
return numF + numOther + numL; }
整理以上代码得 全部代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 32 int getNumber(constchar *num); int power(int length); void swap(int *a,int *b); int main(){ int n,m,numberOfN,numberOfM; while(scanf("%d %d",&n,&m)!=EOF ){ if(n>m) swap(&n,&m); char numN[MAXSIZE]; char numM[MAXSIZE]; sprintf(numN,"%d",n-1); sprintf(numM,"%d",m); numberOfN = getNumber(numN); numberOfM = getNumber(numM); printf("%d\n",numberOfM-numberOfN); //printf("%d\n",n%10 == 1?(numberOfM - numberOfN+1):(numberOfM-numberOfN)); } return0; }
int getNumber(constchar *num){ int firstNum = *num-'0'; int length = strlen(num); int numF,numOther,numL; if(!num || *num < '0' || *num > '9' || *num == '\0') return0; if(length == 1 && firstNum == 0) return0; if(length == 1 && firstNum > 0) return1; numF = 0; if(firstNum > 1) numF = power(length-1); elseif(firstNum == 1) numF = atoi(num+1)+1; numOther = firstNum*(length-1)*power(length-2); numL = getNumber(num+1); return numF + numOther + numL; }
int power(int length){ int i; int result = 1; for(i=0;i<length;i++){ result *= 10; } return result; } void swap(int *a,int *b){ int tmp = *b; *b = *a; *a = tmp; } /************************************************************** Problem: 1373 User: xhalo Language: C Result: Accepted Time:10 ms Memory:916 kb ****************************************************************/