L. Digit sum(规律)
OutputFile
For each test case, output one line containing Case #x: y, where xxx is the test case number (starting from 1) and y is answer.
样例输入
2 10 10 8 2
样例输出
Case #1: 46 Case #2: 13
题意分析:
把1到n中所有的数化为b进制,求各位上的数字之和。
解题思路:
用n=25, b=4来说,25转换成4进制为121。
从第一位开始:这个1出现了多少次?不难发现是 21(4进制)+ 1次,即100, 101, 102, 103, 110, 111, 112, 113, 120 ,121 一共10次,此刻第一位上出现过的数字已经考虑完毕;
接下来是第2位,第一位上的数字是1,说明第二位上的数字已经从0到3跑过1遍,
那我们考虑第1轮, 每一轮每个数字会停留pow(4,1)次,即1会出现4次,即10,11,12,13; 所以每一轮第2位会出现的数字之和为 1*pow(4,1)+2*pow(4,1)+3*pow(4,1)+4*pow(4,1) = 4*(4-1)/2*pow(4, 1) =24; 即当进位是b时, 为b*(b-1)/2*pow(b, i),再乘上轮数。
再考虑一下第2轮,第2轮已经到了2, 之前的1已经完全走过,所以1出现的次数是pow(4,1)=4, 2出现的次数是1(4进制)+1, 一共是2*2=4;此时第2位也已经考虑完了;
第3位,和第2位一样,第三位走过12(4进制)轮,一共是(1*4+2)* 4*(4-1)/ 2 *pow(4, 0) = 36 , 考虑第7轮 1出现了1次是1;第3轮考虑完毕,
所有值加起来是 10 + 24 + 36 + 4 +4 + 1=79。
模拟起来比较复杂,结合代码看会比较好一点。
#include <stdio.h>
#include <math.h>
const int N = 120;
int a[N], len;
void f(int n, int b)
{
if(n==0)
return ;
a[len++]=n%b;
f(n/b, b);
}
int main()
{
int kase=0, t, n, b;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &b);
len=0;
f(n, b);
int ans=0;
int sum=0;
for(int i=len-1; i>=0; i--) {
int sum1=0;
for(int j=i-1; j>=0; j--)
sum1=sum1*b+a[j];
sum1++;
ans+=sum*b*(b-1)/2*pow(b, i);
for(int j=1; j<a[i]; j++)
ans+=j*pow(b, i);
ans+=a[i]*sum1;
sum=sum*b+a[i];
}
printf("Case #%d: %d
", ++kase, ans);
}
return 0;
}