「NOIP2017_Junior」图书管理员

思路

这道题第一眼看上去可以用暴力解

但是

瞥了第二眼数据范围发现三重循环肯定TLE啊

所以

这道题的难点就在于如何优化程序的时间复杂度

当然也可以不优化,以下仅为我的解法,若有更优解欢迎大家提出

会做力

C++STL库自带那么多函数,还有字符串、vector容器等(不用白不用)

OK,引入知识----substr()函数

part1 定义

substr()是C++语言函数,主要功能是复制子字符串,要求从指定位置开始,并具有指定的长度。如果没有指定长度_Count或_Count+_Off超出了源字符串的长度,则子字符串将延续到源字符串的结尾。——摘自百科词条

part2 使用形式

string s;

s.substr(pos, len);
part3 返回值

返回值类型为string字符串类型,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,说人话就是不加参数会默认拷贝整个s)

part4 异常情况

若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+len的值超过了string的大小,则substr会调整len的值,只拷贝到string的末尾(说人话就是能复制就复制,不能复制就报错)

tips:头文件别忘了

都介绍到这了,该实现这道题了(细节还是蛮多的

有substr函数了,就可以开始优化了

我知道你很急,但你先别急

因为题中的图书编码是字符串类型要定义成二维的

该输入了

代码实现如下

string book[1001];

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

    cin >> book[i];

}

为啥看着像一维呢

因为他和vector容器一样,具有动态大小的特性,通过[]符号访问下标其实是访问他的第二维(说人话就是第一维不定义,其空间大小由其中字符多少决定;字符串的第二维看着像普通数组的第一维,实际就是普通数组的第二维,能用下标访问

输入完以后,sort快速&&方便地排一下序,加cmp函数找最小值

注意字符串类型cmp函数的实现

bool cmp(string a, string b) {

    if (a.size() != b.size()) {

        return a.size() < b.size();

    }

    return a < b;

}

主函数内第二个循环(第一个循环是输入)

第一重循环内正常输入图书馆里读者的需求码的长度和读者的需求码,并定义一个bool类型初值为假的变量flag用来标记有没有读者所需要的书

第二重循环开始遍历book字符串数组,若该字符串的长度小于读者需求码的长度,continue跳过;否则用substr函数判断读者的需求码与当前book字符串数组的末尾是否相等,若相等输出当前的book字符串,flag标记为真并break结束该循环

第二重循环结束后,在第一重循环的末尾判断flag是否为;若是,输出-1

最后,Ac代码如下
#include<bits/stdc++.h>

using namespace std;

string book[1001];

bool cmp(string a, string b) {

    if (a.size() != b.size()) {

        return a.size() < b.size();

    }

    return a < b;

}

int main() {

    freopen("librarian.in","r",stdin);

    freopen("librarian.out","w",stdout);

    int n, q;

    cin >> n >> q;

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

        cin >> book[i];

    }

    sort(book+1, book + n+1, cmp);

    for (int i = 1; i<=q; i++) {

        int len;

        string num;

        cin >> len >> num;

        bool flag = false;

        for (int j = 0; j<=n; j++) {

            if (book[j].size() < len) {

                continue;

            }

            else {

                if (book[j].substr( book[j].size() - len, len) == num) {

                    cout << book[j] << endl;

                    flag = true;

                    break;

                }

            }

        }

        if (flag==0) {

            cout << -1 << endl;

        }

    }

    return 0;

}

对了*1

发完这篇题解后想到用字符数组解也不是不行(目前尚未实现)

对了*2

等等,好像int数组数位分离再比较也可以啊

上网查了一下资料后发现这道题用数位分离法做的比较多,而且不用cmp函数也可以

实在打不动字了,Ac代码如下,看注释吧

#include<bits/stdc++.h>

using namespace std;

int n,q,book[1005],num,len,x;

int main() {

    freopen("librarian.in","r",stdin);

    freopen("librarian.out","w",stdout);

    cin>>n>>q;

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

        cin>>book[i];

    }

    sort(book+1,book+n+1);//快排 保证找到的图书编号最小

    for(int i=1; i<=q; i++) {

        bool f=0;//假设找不到读者的书

        cin>>len>>num;//输入需求码的长度和读者需求码

        //w是10的len次方(用于判断图书的后len位)

        long long w=pow(10,len);

        for(int j=1; j<=n; j++) { //寻找图书

            x=book[j]%w;//x是book[j]的末len位

            if(x==num) { //若能找到

                cout<<book[j]<<endl;//输出图书编号

                f=1;//标记找到了读者的书

                break;//找到就不用再找了,因为要输出最小的

            }

        }

        if(f==0) {

            cout<<"-1"<<endl;//若找不到输出-1

        }

    }

    return 0;

}

恍然大悟

(我发帖查资料的样子真的很狼狈)




 

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值