/**//* 两种操作 1)询问[x,y]区间内,base进制下,一个数的各位之和为M的个数 2)询问[x,y]区间内,第K大各位之和为M的数 数位统计,预处理dp[len][j]在base进制下,长度为len各位之和为j的个数 然后逐位统计 对于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; }
|