666
题意,从小到大,去掉有4和13的数,要求第n位数是多少。
用dp[l][t]表示长为l位的,t = 0表示没有限制 t =1 表示最后一位是1,t = 2表示结束为4或者是13的个数。则任何一个数,都可以很快转化成dp[l][t]来求解,如果是同一位数,很对应的那么数开始计数,否则从9开始计数,记忆化搜索就可以了。得到了个数,可以用个二分的方法,找到答案就可以了。不过这题有个坑,如果是10^18这个数,就是用long long是会爆的,要用unsinged long long,总的复杂度为log(n0) * log(n)
#define N 100
#define ll unsigned long long
#define INF 18223372036854775800
ll pri[N],dp[N][3];
ll get(ll d,ll t){
if(d==2||t==4||(d==1&&t==3))return 2ll;
if(t==1)return 1ll;
return 0ll;
}
ll dfs(ll pos,ll d,ll flag){
if(pos==0)return d==2;
if(!flag&&dp[pos][d]!=-1)return dp[pos][d];
ll u=flag?pri[pos]:9,ans=0;
for(ll i=0;i<=u;i++)
ans+=dfs(pos-1,get(d,i),flag&&(i==u));
return flag?ans:dp[pos][d]=ans;
}
ll solve(ll x){
ll cnt=0,tx = x;
while(x){
pri[++cnt]=x%10;
x/=10;
}
ll temp = tx - dfs(cnt,0,1);
return temp;
}
ll getans(ll n){
ll l = 1,r = INF,mid;
while(l < r - 1){
mid = l + (r - l)/2;
ll x = solve(mid);
if(x < n) l = mid;
else r = mid;
}
if(solve(l) == n) return l;
if(solve(r) == n) return r;
return 0;
}
int main()
{
ll n;
memset(dp,-1,sizeof(dp));
while(cin>>n){
ll temp = getans(n);
cout<<temp<<endl;
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/mengzhengnan/article/details/47664855