 /**//*
兩種操作
1)詢問[x,y]區(qū)間內,base進制下,一個數(shù)的各位之和為M的個數(shù)
2)詢問[x,y]區(qū)間內,第K大各位之和為M的數(shù)
數(shù)位統(tǒng)計,預處理dp[len][j]在base進制下,長度為len各位之和為j的個數(shù)
然后逐位統(tǒng)計
對于2)需要二分,注意的是(high+low)會超int,要用long long,不然超時
很陰的是輸入的X可能>Y , hdu的 assert() RE是返回wa的
*/
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int MAXN = 310;

int dp[40][MAXN];

void init(int base , int limit)
  {
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i <= 31 ; i++)
 {
for(int j = 0 ; j <= limit ; j++)
for(int k = 0; k < base && j - k >= 0 ; k++)
dp[i][j] += dp[i-1][j-k];
}
}

int cal(int x, int base , int M)//cal [1,x)
  {
int bit[40] , len = 0;
while(x)
 {
bit[++len] = x%base;
x/=base;
}
int ans = 0 , preSum = 0;
for(int i = len ; i > 0 ; i --)
 {
for(int j = 0 ; j < bit[i] && M-preSum-j >= 0 ; j++)
ans += dp[i-1][M-preSum-j];
preSum += bit[i];
}
return ans;
}

int main()
  {
#ifdef ONLINE_JUDGE
#else
freopen("in","r",stdin);
#endif
int Q , X , Y , B , M , K;
int t = 1;
while( ~scanf("%d%d%d%d%d",&Q,&X,&Y,&B,&M) )
 {
printf("Case %d:\n",t++);
init(B,M);
if(X > Y) swap(X,Y); //need !!!!
if(Q==1)printf("%d\n",cal(Y+1,B,M) - cal(X,B,M));
else
 {
scanf("%d",&K);
K += cal(X,B,M);
int low = X , high = Y;
while(high >= low)
 {
int mid = (0LL + high + low )>>1; //exceed int
if(cal(mid+1,B,M)>=K)high = mid - 1;
else low = mid + 1;
}
if(low == Y + 1)puts("Could not find the Number!");
else printf("%d\n",low);
}
}
return 0;
}



|