牛客-[NOIP2017]图书管理员——字典树or排序取模

题目

题目链接

题目详解

这题也有两种做法,而且都不慢。

  1. 改造字典树的做法:
    我们用书的编号建立字典树,每次插入一段编号,从尾部开始分解,进行字典树的建立,字典树的每一个结点存下这个尾部对应的最大前缀即可。建立好字典树后,查找过程也只需要查查一下即可得到结果。时间复杂度插入为O(n),查询为O(n),这里的n指的都是编号的长度。实际上此题编号长度不会超过9,所以完全可以视作是常数级别的复杂度。所以整个插入和查询过程可以看作是O(n)和O(m)的复杂度,n表示要插入的编号个数,m表示要查询的个数。
  2. 直接排序强行枚举(本题的正统解法):
    由于本题的数据量都不超过一个int,所以把图书编号存下来排好序,而正好输入的数据有所需图书编号的位数,所以直接可以通过取模判断图书编号是否以该所需编号结尾!而得到的第一个结果正好就算最小值了。

解题代码

法一:字典树

#include<bits/stdc++.h>
using namespace std;

struct node{
    int remain_minV;//TODO 每个结点存下到了这个位置之后的最小剩余量。
    node* next[10];
    node(){
        remain_minV = INT_MAX;
        memset(next,0,sizeof(next));
    }
    node(int val){
        remain_minV = val;
        memset(next,0,sizeof(next));
    }
    void update(int val){
        remain_minV = min(remain_minV,val);
    }
};
//TODO 字典树实现
struct Trie{
    node root;
    void add(int val){
        int data = val;
        node* cur = &root;
        while (data){
            int c = data%10,pre = data/10;
            if(!cur->next[c]){
                cur->next[c] = new node(pre);
            }else{
                cur->next[c]->update(pre);
            }
            cur = cur->next[c];
            data/=10;
        }
    }
    int find(int src){
        int data = src;
        node* cur = &root;
        bool f = true;
        while (data){
            int c = data%10;
            if(cur->next[c]==0){
                f = false;
                break;
            }
            cur = cur->next[c];
            data /= 10;
        }
        if(!f)return -1;
        string sum = to_string(cur->remain_minV)+to_string(src);
        return atoi(sum.c_str());
    }
};
//TODO 具体的使用,就只需要调用我实现的数据结构即可
int main(){
    ios::sync_with_stdio(false);
    int p,q;cin>>p>>q;
    int book_code,need_code;
    Trie check;
    while (p--){
        cin>>book_code;
        check.add(book_code);
    }
    while (q--){
        int t;cin>>t>>need_code;
        cout<<check.find(need_code)<<'\n';
    }
    return 0;
}

法二:排序+取模判断

#include<cstdio>
#include<algorithm>
#include<cmath>
const int N=1000;
int n,m,a[N+5];
int mod,reader;
bool f;
int readint()
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x;
}
int main()
{
    n=readint();m=readint();
    for(int i=1;i<=n;i++)
        a[i]=readint();
    std::sort(a+1,a+n+1);//TODO 排序
    for(int i=1;i<=m;i++)
    {
        mod=(int)pow(10,readint());
        reader=readint();
        f=1;
        for(int i=1;i<=n;i++)
            if(a[i]%mod==reader)//TODO 取模判断
            {
                printf("%d\n",a[i]);
                f=0;
                break;
            }
        if(f) printf("-1\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值