从组合数 以及 数位DP的角度都可以做……
首先转化成求1~n内K进制下只有0、1的数的个数:
考虑K进制下第一个为1的位,剩下的数位中0和1随便放……也就是算组合数了。
然后区间相减……
写的好乱……还是去看论文吧
1 //Ural 1057
2 #include<cstdio>
3 #include<cstring>
4 #include<cstdlib>
5 #include<iostream>
6 #include<algorithm>
7 #define rep(i,n) for(int i=0;i<n;++i)
8 #define F(i,j,n) for(int i=j;i<=n;++i)
9 #define D(i,j,n) for(int i=j;i>=n;--i)
10 using namespace std;
11
12 int getint(){
13 int v=0,r=1; char ch=getchar();
14 for(;ch<'0' || ch>'9';ch=getchar()) if (ch=='-') r=-1;
15 for(;ch>='0'&&ch<='9';ch=getchar()) v=v*10+ch-'0';
16 return v*r;
17 }
18 /*******************template********************/
19 int f[40][40];
20 void init(){
21 f[0][0]=1;
22 F(i,1,31){
23 f[i][0]=f[i-1][0];
24 F(j,1,i) f[i][j]=f[i-1][j]+f[i-1][j-1];
25 }
26 }
27 int calc(int x,int k){
28 int tot=0,ans=0;
29 D(i,31,1){
30 if (x&(1<<i)){
31 ++tot;
32 if(tot>k)break;
33 x=x^(1<<i);
34 }
35 if ( (1<<(i-1))<=x )
36 ans+=f[i-1][k-tot];
37 }
38 if (tot+x==k) ++ans;
39 return ans;
40 }
41 int a[40];
42 int change(int x,int b){
43 int l=0;
44 for(l=0;x;l++,x/=b) a[l]=x%b;
45 D(i,l-1,0) if (a[i]>1){
46 D(j,i,0) a[j]=1;
47 break;
48 }
49 int temp=0;
50 D(i,l-1,0) temp=(temp<<1)+a[i];
51 return temp;
52 }
53 int main(){
54 // freopen("input.txt","r",stdin);
55 init();
56 int l=getint(),r=getint(),k=getint(),b=getint();
57 int ans=0;
58 if (b!=2) ans=calc(change(r,b),k)-calc(change(l-1,b),k);
59 else ans=calc(r,k)-calc(l-1,k);
60 printf("%d\n",ans);
61 return 0;
62 }