题意:给m,n,问含有m个0的第k个数,是几位数,并且最高位是多少。
思路:和普通数位dp一样,加上个二分。
然后就是注意一下,极限值测试下能否算出来,这题极限值很大!
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
//2014年9月24日17:07:38
__int64 dp[22][22][11];
int num[22];
__int64 dfs(int site,int n,int m,int zero,int f)
{
if(site==0)
{
if(zero) return 0;
return n==m?1:0;
}
if(!f&&!zero&&~dp[site][n][m]) return dp[site][n][m];
int len=f?num[site]:9;
__int64 ans=0;
for(int i=0; i<=len; i++)
{
if(zero) ans+=dfs(site-1,n,m,zero&&i==0,f&&i==len);
else
{
if(i==0) ans+=dfs(site-1,n+1,m,zero&&i==0,f&&i==len);
else ans+=dfs(site-1,n,m,zero&&i==0,f&&i==len);
}
}
if(!f&&!zero) dp[site][n][m]=ans;
return ans;
}
__int64 solve(__int64 x,int m)
{
if(x<0) return 0;
int cnt=0;
while(x)
{
num[++cnt]=x%10;
x/=10;
}
return dfs(cnt,0,m,1,1);
}
int main()
{
int t;
cin>>t;
memset(dp,-1,sizeof(dp));
while(t--)
{
__int64 k;
int m;
scanf("%d%I64d",&m,&k);
__int64 l=1,r=9000000000000000000LL,mid,ans;
while(l<=r)
{
mid=(l+r)/2;
if(solve(mid,m)>=k)
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
__int64 len,tt=1,n;
len=(__int64)log10(ans*1.0)+1;
n=len-1;
while(n--) tt*=10;
printf("%I64d %I64d\n",len,ans/tt);
//printf("%I64d\n",ans);
}
return 0;
}
//2014年9月24日18:07:25