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

Posted C+++++++++++++++++++

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客-[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;

以上是关于牛客-[NOIP2017]图书管理员——字典树or排序取模的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2017-普及组复赛第2题 题解

NOIP2017普及组赛后心得

牛客小白月初赛-卷王之王(优先队列or线段树)

牛客小白月初赛-卷王之王(优先队列or线段树)

4889: [Tjoi2017]不勤劳的图书管理员 树套树

牛客-[NOIP2012]借教室——差分数组的运用