数位DP
从组合数 以及 数位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 ",ans); 61 return 0; 62 }