思路:二维树状数组+区间求和
#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;
}
来源:https://blog.csdn.net/weixin_43888067/article/details/102489099