【题目链接】
ybt 1415:【17NOIP普及组】图书管理员
洛谷 P3955 [NOIP2017 普及组] 图书管理员
【题目考点】
1. 枚举
2. 二分
【解题思路】
解法1:枚举
对于每个读者,需求码长度为len,需求码为code,图书编码存入book数组。
枚举所有图书编码,求满足该读者需求的图书中图书编码的最小值。
这里可以预处理出一个数组p,p[i]
为
1
0
i
10^i
10i。
求数值x末len位的方法:x%p[len]
,
- 枚举对象:图书编码
- 枚举范围:所有的图书
- 判断条件:判断图书编码末len位与读者需求码code是否相同。
求满足该读者需求的图书编码中的最小值。
复杂度: O ( q ⋅ n ) O(q\cdot n) O(q⋅n)
解法2:排序+顺序查找
可以先对book数组进行升序排序,而后对于每个读者,在book数组中顺序查找满足图书编码末len位与读者需求码code相同的第一个图书编码,该编码就是满足条件的图书编码中的最小值。
复杂度:
O
(
q
⋅
n
)
O(q\cdot n)
O(q⋅n)、
解法3:排序+二分查找
可以先对book数组进行升序排序,而后对于每个读者,在book数组中二分查找满足图书编码末len位与读者需求码code相同的第一个图书编码。这就要求图书编码关于末len位有序(如果末len位相同,那么图书编码小的排在前)。
题目要求图书编码不超过
1
0
7
10^7
107,因此对图书编码分别按照:末1位,末2位,…,末7位升序进行7次排序,得到7个有序序列。按照末i位排序得到的有序序列为b[i]
。
如果要找满足图书编码末len位与读者需求码code相同的第一个图书编码,那么就在b[len]
数组中二分查找末len位大于等于code的最小值。如果该最小值末len位与code相同,那么输出该最小值,否则输出-1。
得到7个有序序列b[1]
~b[7]
的复杂度为
O
(
q
⋅
l
o
g
q
)
O(q\cdot log q)
O(q⋅logq)
对于每个读者查找图书编码的复杂度为
O
(
n
⋅
l
o
g
q
)
O(n\cdot log q)
O(n⋅logq)
整体复杂度:
O
(
(
q
+
n
)
⋅
l
o
g
(
q
)
)
O((q+n)\cdot log(q))
O((q+n)⋅log(q))
【题解代码】
解法1:枚举
#include <bits/stdc++.h>
using namespace std;
#define N 1005
#define INF 0x3f3f3f3f
int book[N], p[10];//p[i]:10^i的值
void initP()
{
p[0] = 1;
for(int i = 1; i <= 7; ++i)//图书编码和需求码都不大于10^7,所以最大用到10^7
p[i] = p[i-1]*10;
}
int main()
{
initP();
int n, q, len, code;
cin >> n >> q;
for(int i = 1; i <= n; ++i)
cin >> book[i];//book[i]:第i本书的图书编码
for(int i = 1; i <= q; ++i)
{
cin >> len >> code;
int minCode = INF;
for(int j = 1; j <= n; ++j)
if(book[j]%p[len] == code)
minCode = min(minCode, book[j]);
cout << (minCode == INF ? -1 : minCode) << endl;
}
return 0;
}
解法2:排序+顺序查找
#include <bits/stdc++.h>
using namespace std;
#define N 1005
int book[N], p[10];//p[i]:10^i的值
void initP()
{
p[0] = 1;
for(int i = 1; i <= 7; ++i)//图书编码和需求码都不大于10^7,所以最大用到10^7
p[i] = p[i-1]*10;
}
int main()
{
initP();
int n, q, len, code;
cin >> n >> q;
for(int i = 1; i <= n; ++i)
cin >> book[i];//book[i]:第i本书的图书编码
sort(book+1, book+1+n);//升序排序
for(int i = 1; i <= q; ++i)
{
cin >> len >> code;
bool isFound = false;
for(int j = 1; j <= n; ++j)
{
if(book[j]%p[len] == code)
{
cout << book[j] << endl;
isFound = true;
break;
}
}
if(isFound == false)
cout << -1 << endl;
}
return 0;
}
解法3:排序+二分查找
- 写法1:设多个函数 手写二分查找
#include <bits/stdc++.h>
using namespace std;
#define N 1005
int n, q, b[8][N], book[N], p[10];//p[i]:10^i的值 b[i]:book按照cmpi比较得到的有序序列
void initP()
{
p[0] = 1;
for(int i = 1; i <= 7; ++i)//图书编码和需求码都不大于10^7,所以最大用到10^7
p[i] = p[i-1]*10;
}
//cmpl:a、b的末l位先比较,小的排在前。如果相等,a、b中较小的排在前。
bool cmp1(int a, int b)
{
return a%10 == b%10 ? a < b : a%10 < b%10;
}
bool cmp2(int a, int b)
{
return a%100 == b%100 ? a < b : a%100 < b%100;
}
bool cmp3(int a, int b)
{
return a%1000 == b%1000 ? a < b : a%1000 < b%1000;
}
bool cmp4(int a, int b)
{
return a%10000 == b%10000 ? a < b : a%10000 < b%10000;
}
bool cmp5(int a, int b)
{
return a%100000 == b%100000 ? a < b : a%100000 < b%100000;
}
bool cmp6(int a, int b)
{
return a%1000000 == b%1000000 ? a < b : a%1000000 < b%1000000;
}
bool cmp7(int a, int b)
{
return a%10000000 == b%10000000 ? a < b : a%10000000 < b%10000000;
}
void initB()
{
for(int i = 1; i <= 7; ++i)
memcpy(b[i], book, sizeof(book));//先复制book到b[i]
sort(b[1]+1, b[1]+1+n, cmp1);
sort(b[2]+1, b[2]+1+n, cmp2);
sort(b[3]+1, b[3]+1+n, cmp3);
sort(b[4]+1, b[4]+1+n, cmp4);
sort(b[5]+1, b[5]+1+n, cmp5);
sort(b[6]+1, b[6]+1+n, cmp6);
sort(b[7]+1, b[7]+1+n, cmp7);
}
int main()
{
initP();
int len, code;
cin >> n >> q;
for(int i = 1; i <= n; ++i)
cin >> book[i];//book[i]:第i本书的图书编码
initB();
for(int i = 1; i <= q; ++i)
{
cin >> len >> code;
int l = 1, r = n, m;//二分查找b[len]中模p[len]后大于等于code的最小值
while(l < r)
{
m = (l+r)/2;
if(b[len][m]%p[len] >= code)
r = m;
else
l = m+1;
}
if(b[len][l]%p[len] == code)//如果找到的图书编号b[len][mi]的末len位就是要找的code
cout << b[len][l] << endl;
else
cout << -1 << endl;
}
return 0;
}
- 写法2:使用lambda表达式,lower_bound函数
#include <bits/stdc++.h>
using namespace std;
#define N 1005
int n, q, b[8][N], book[N], p[10];//p[i]:10^i的值 b[i]:book按照cmpi比较得到的有序序列
void init()
{
p[0] = 1;
for(int i = 1; i <= 7; ++i)
{
p[i] = p[i-1]*10;//图书编码和需求码都不大于10^7,所以最大用到10^7
memcpy(b[i], book, sizeof(book));//复制book到b[i]
sort(b[i]+1, b[i]+1+n,
[i](int a, int c)//用lambda表达式来写比较函数,捕获使用外面的变量i
{
return a%p[i] == c%p[i] ? a < c : a%p[i] < c%p[i];
}
);
}
}
int main()
{
int len, code;
cin >> n >> q;
for(int i = 1; i <= n; ++i)
cin >> book[i];//book[i]:第i本书的图书编码
init();
for(int i = 1; i <= q; ++i)
{
cin >> len >> code;
int m = lower_bound(b[len]+1, b[len]+1+n, code, [len](int a, int c){return a%p[len] < c%p[len];}) - b[len];
if(b[len][m]%p[len] == code)//如果找到的图书编号b[len][mi]的末len位就是要找的code
cout << b[len][m] << endl;
else
cout << -1 << endl;
}
return 0;
}