【题解】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;
}