字典序排序n!

题意:

给出n和k,将1~n按字典序排序,问第k个是几


这道题限制蛮大, 不是时间超限就是内存超限,不能把1~n或者是1~k列出,按字典树列出也不可以,只能找规律做,上面这个代码是学长的找规律做的,下面那个代码是我用字典树做的,内存超限


这个代码很巧妙,我想这样做可是智商不够没有想出来

#include<stdio.h>

#include<iostream>

#include<cmath>

#include<algorithm>

#include<string.h>

using namespace std;

int N = 100010;

int qianz(int n,int i) //i为前缀的  小于N的数有多少个

{

    

    int y = i + 1, num = 0;

    while(i <= n)

    {

        num += min(y,n + 1) - i;

        i *= 10, y *= 10;

        

    }

    return num;

}

int main()

{

    

    int t, n, k,s;

    scanf("%d",&t);

    while(t--)

    {

        scanf("%d%d",&n,&k);

        s = 1;

        k--;

        while(k)

        {

            int num = qianz(n, s);

            if(num <= k)

            {

                k -= num;

                s++;

            }

            else

            {

                k--;

                s *= 10;

            }

        }

        printf("%d\n",s);

    }

}



用字典树做(超内存)


#include <iostream>

#include <cstdio>

#include <algorithm>

#include <cstring>

#include <cmath>

#include <cstdlib>

using namespace std;

int n,k;

int ans[25],an;

int sum[10];

struct node

{

    bool flag;

    node *next[11];

   // int sum;

}*root;

node *build()

{

    node *p = (node *)malloc(sizeof(node));

    for(int i = 0; i < 10; i ++)

        p -> next[i] = NULL;

    p -> flag = false;

    //p->sum=0;

    return p;

}

void save(char *s)

{

    node *p;

    p = root;

    int len = strlen(s);

    for(int i = 0; i < len; i ++)

    {

        if(p -> next[s[i] - '0'] == NULL)

            p -> next[s[i] - '0'] = build();

        if(p==root)

            sum[s[i]-'0']++;

        p = p -> next[s[i] - '0'];

    }

    p -> flag = true;

}

int kk;

void query(node *p)

{

    if(kk==k)

        return;

    

    for(int i = 0; i <= 9; i ++)

    {

        if(p -> next[i] != NULL)

        {

            //printf("(%d %d) ",i,kk);

            if(p->next[i]->flag==true)

               kk++;

            query(p->next[i]);

            if(kk==k)

            {

                ans[an++]=i;

                return;

            }

        }

        

    }

    return;

}

void clear(node *p)

{

    for(int i = 0; i < 10; i ++)

    {

        if(p -> next[i] != NULL)

            clear(p -> next[i]);

        p -> next[i] = NULL;

    }

    return;

}

int main()

{

    

    char str[25];

    int s[25];

    int t;

    cin>>t;

    while(t--)

    {

        root = build();

        scanf("%d %d",&n,&k);

        memset(sum,0,sizeof(sum));

        for(int i=1;i<=n;i++)

        {

            int num=i,f=0;

            while(num!=0)

            {

                s[f++]=num%10;

                num=num/10;

            }

            for(int j=f-1;j>=0;j--)

            {

                str[f-1-j]=s[j]+'0';

                //printf("%c",str[f-1-j]);

            }

            save(str);

            //cout<<endl;

        }

        kk=0;

        node *p;

        p = root;

        int i=1;

        for(i=1;i<=9;i++)

        {

            if(p->next[i]==NULL)

                continue;

            

            if(sum[i]<k)

            {

                k=k-sum[i];

            }

            else

                break;

        }

        an=0;

        memset(ans,0,sizeof(ans));

        //printf("i=%d\n",i);

        k--;

        query(p->next[i]);

        ans[an++]=i;

        for(int i=an-1;i>=0;i--)

            printf("%d",ans[i]);

        cout<<endl;

        clear(p);

    }

    return 0;

}



/************************************


这几天可能太紧张了吧,昨晚梦到了高考,不是回到了高三,而是现在紧张兮兮的想补学点什么,觉得没有学够。讲真我高三的时候都没有这样的心态的


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值