标签:
Problem E666
题意,从小到大,去掉有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