【题解】1585: 【例 1】Amount of Degrees

\(Description:\)

给出一个区间 \([L,R]\) ,要求这区间内满足由 \(k\) 个不同的 \(B\) 的幂次的数组成

\(Sample\) \(Input:\)

15 20 2 2

\(Sample\) \(Output:\)

3

\(Solution:\)

首先这题可以写暴力,过50分,爽快。

对于暴力考虑剪枝,很简单,倒着搜索,每次让枚举范围变小,可以过78分。

正解肯定是数位dp,考试的时候也不是没想到,就是没理解一个性质:

一个 \(B\) 进制数最高位为 \(1\) 那么不管后面怎么填都不会比他大。

同时这题还要注意只有当枚举范围变成 \(digit\) 是才算 \(limit\)

从今开始改善码风~~

#include<cstdio>
#include<cstring>
#include<algorithm>

using std::min;
using std::scanf;
using std::printf;
using std::memset;

typedef long long LL;
const int N=35,M=25;

LL l,r,B;
int k;
int digit[N];
LL  f[N][M];
inline LL dfs(int len,int num,bool limit){
	if(num>k) return 0;
	if(len+num<k) return 0;
	if(len==0) return num==k;
	if(!limit && f[len][num]!=-1) return f[len][num];
	int up_bound=(limit && !digit[len])?digit[len]:1;
	LL ret=0;
	for(int i=0;i<=up_bound;++i)
		ret+=dfs(len-1,num+(i==1),limit&&(i==digit[len]));
	if(!limit) f[len][num]=ret;
	return ret;
}
inline LL solve(LL x){
	int cnt=0;
	memset(f,-1,sizeof(f));
	while(x>0) digit[++cnt]=x%B,x/=B;
	return dfs(cnt,0,true);
}
int main(){
	scanf("%lld%lld%d%lld",&l,&r,&k,&B);
	printf("%lld\n",solve(r)-solve(l-1));
	return 0;
}

posted @ 2019-04-24 21:50  章鱼那个哥  阅读(399)  评论(0编辑  收藏  举报