VIrtuoso

两把多兰剑加个布甲鞋

导航

hdu6468 dfs剪枝 or char数组 or 构造

http://acm.hdu.edu.cn/showproblem.php?pid=6468

题意

有一个序列,是1到n的一种排列,排列的顺序是字典序小的在前,那么第k个数字是什么?(\(1 \leq n \leq 10^6,1 \leq k \leq n,多组T\leq 100\))

题解1

  • 假如剪枝好的话,每次最多搜1e6,这样总共1e8,能过
  • dfs序>=k剪掉,num>n剪掉
#include<bits/stdc++.h>

using namespace std;
int dfn,n,k,ans,T;
void dfs(int num){
    if(dfn>=k)return;
    dfn++;
    //cout<<num<<" "<<dfn<<endl;
    if(dfn==k){ans=num;return;}
    int l=(!num?1:0);
    for(int i=l;i<=9;i++){
        if(num*10+i>n)return;  //continue就超时了
        dfs(num*10+i);
    }
}
int main(){
    cin>>T;
    while(T--){
        dfn=-1;
        scanf("%d%d",&n,&k);
        dfs(0);
        printf("%d\n",ans);
    }
}

题解2

https://www.twblogs.net/a/5c92e1f9bd9eee35cd6ba3b7/zh-cn

  • 预处理出所有字符串,排序,O(6nlog(6*n))
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=1e6;
const int MM=192600817;
struct A
{
    ll k;
    char  s[8];
}a[MAX+1];
bool cmp(struct A p,struct A q)
{
    return strcmp(p.s,q.s)<0;
}
int main()
{
    ll T,n,k,i,j;
    for(i=1;i<=MAX;i++)
    {
        a[i].k=i;
        ll t=i,e=0,m;
        while(t)
        {
            a[i].s[e]=(t%10)+'0';
            t/=10;
            e++;
        }
        for(j=0;j<e/2;j++)
        {
            char tt;
            tt=a[i].s[j];
            a[i].s[j]=a[i].s[e-j-1];
            a[i].s[e-j-1]=tt;
        }
    }
    sort(a+1,a+MAX+1,cmp);
    //cout<<a[1000].s<<endl;
    cin>>T;
    while(T--)
    {
        cin>>n>>k;
        i=1;
        for(i=1;i<=MAX;i++)
        {
            if(a[i].k>n)
                continue;
            else
                k--;
            if(k==0)
                break;
        }
        cout<<a[i].k<<endl;
    }
    return 0;
}

题解3

https://zeng1998.github.io/2019/03/16/hdu6468——zyb的面试/

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
ll solve(ll n,ll m){
    //考虑一颗完全10叉树,树的所有节点就是1-n,要求的就是前序遍历的第m个节点
    //m是可以走的步数
    ll i=1;
    m--;
    while(m!=0){
        //计算i到i+1的字典序中间相隔的个数
        ll s=i,e=i+1;
        ll num=0;
        //防止越界
        while(s<=n){
            //计算每一层相差的个数
            //n+1: 比如20-29其实是10个,而e就不用+1,因为e在这里表示30(40/50...)
            num+=min(n+1,e)-s;
            s*=10;
            e*=10;
        }
        if(m<num){
            //向下
            i*=10;
            //走一步
            m--;
        }else{
            //向右
            i++;
            //对前序遍历来说,走了num步
            m-=num;
        }
    }
    return i;
}
int t;
ll n, m;
int main() {
    scanf("%d",&t);
	while (t--){
        scanf("%lld%lld",&n,&m);
        printf("%lld\n",solve(n,m));
    }
	return 0;
}

posted on 2019-05-05 23:37  VIrtuoso  阅读(184)  评论(0编辑  收藏  举报