题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3271
题意:
有两种询问:
q=1,在[x,y]区间内,转换成b进制数,数位和为m的有多少个;
q=2,在[x,y]区间内,转换成b进制数,数位和是m的第k个数是多少(十进制)
源代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
typedef __int64 LL;
LL dp[35][305];//dp[i][j]表示长度为i数位和为j时的数的个数
int num[35];
int m,b;
LL dfs(int len,int nowsum,bool limit)
{
if(len==0)
return nowsum==m;
if(!limit && dp[len][nowsum]!=-1)
{
return dp[len][nowsum];
}
int mmax=limit?num[len]:b-1;
__int64 ans=0;
for(int i=0; i<=mmax; i++)
{
ans+=dfs(len-1,nowsum+i,limit && i==mmax);
}
if(!limit)
{
dp[len][nowsum]=ans;
}
return ans;
}
LL solve(LL n)
{
if(n<=0)
return 0;
int cnt=0;
while(n)
{
num[++cnt]=n%b;
n/=b;
}
return dfs(cnt,0,true);
}
LL Search(LL l,LL r,LL k)
{
LL ans=-1;
LL x=l-1;
while(l<=r)
{
LL mid=(l+r)/2;
if(solve(mid)-solve(x-1)>=k)
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
int main()
{
int op;
LL x,y;
int cas=1;
while(~scanf("%d",&op))
{
memset(dp,-1,sizeof dp);
printf("Case %d:\n",cas++);
if(op==1)
{
scanf("%I64d%I64d%d%d",&x,&y,&b,&m);
if(x>y)
swap(x,y);
x--;
printf("%I64d\n",solve(y)-solve(x));
}
else if(op==2)
{
LL k;
scanf("%I64d%I64d%d%d%I64d",&x,&y,&b,&m,&k);
if(x>y)
swap(x,y);
LL ans=Search(x,y,k);
if(ans==-1)
{
puts("Could not find the Number!");
}
else
{
printf("%I64d\n",ans);
}
}
}
return 0;
}