The Preliminary Contest for ICPC Asia Shanghai 2019

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;
} 
原文地址:https://www.cnblogs.com/zyq1758043090/p/11852497.html