L. Digit sum (ICPC 2019 上海网络赛)

随声附和 提交于 2019-12-01 05:52:31

题目传送门

思路:二维树状数组+区间求和

#include<iostream>
using namespace std;
const int MAXN = 1000001;
int c[11][MAXN];
int calc(int n,int b)
{
	int res=0;
	while(n)
	{
		res += (n%b);
		n/=b;
	}
	return res;
}
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int y,int val)
{
	while(y<MAXN)
	{
		c[x][y]+=val;
		y+=lowbit(y);
	}
}
int Sum(int x,int y)
{
	int sum = 0;
	while(y>0)
	{
		sum+=c[x][y];
		y-=lowbit(y);
	}
	return sum;
}
void init() //将二到十进制的所有数的情况计算出来,且对每个进制建立一个树状数组 
{
	for(int i=2;i<=10;i++)
	{
		for(int j=1;j<MAXN;j++)
		{
			int val = calc(j,i);
			add(i,j,val);
		}
	}
}
int main()
{
	int T,id=1;
	init();
	scanf("%d",&T);
	while(T--)
	{
		int n,b;
		scanf("%d%d",&n,&b);
		printf("Case #%d: %d\n",id++,Sum(b,n));
	}
	return 0;
}

思路:同时优化复杂度

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6+10;
int a[10][N];
long long sum[10][N];
int k;

void find(int n)
{
	for(int h=2;h<=10;++h)
	{
		sum[h-2][0] = 0;
		for(int i=0;i<h;i++)
			a[h-2][i] = i;
		for(int i=h;i<=n;i*=h)
			for(int k=1;k<h && i*k <=n;++k)
				for(int j=0;j<i && i*k+j<=n;++j)
					a[h-2][i*k+j] = a[h-2][j]+k;
        for(int i=1;i<=n;i++)
            sum[h-2][i] = a[h-2][i] + sum[h-2][i-1];
	}
}

int main()
{
	int t;
	scanf("%d",&t);
	int x=1;
	clock_t start, finish;
	start = clock();
	find(N);
	finish = clock();
	double duration = (double)(finish - start) / CLOCKS_PER_SEC;
	printf( "%f seconds\n",duration);
	while(t--)
	{
		int n,b;
		scanf("%d %d",&n,&b);
//		bug(n);
		printf("Case #%d: %d\n",x,sum[b-2][n]);
		x++;
	}
	return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!