IQ测试 \operatorname{IQ测试} IQ测试
题目链接: jzoj 5048 \operatorname{jzoj\ 5048} jzoj 5048
题目
PTY进行IQ测试,测试的项目是判断一个序列是否是另外一个序列删除若干个数字之后得到的,PTY 深知自己的IQ 低于 s q r t ( − 1 ) sqrt(-1) sqrt(−1) ,所以他请来了智商超高的你来替他解决问题。
输入
第一行为一个整数 n n n ,第二行包括 n n n 个用空格分开的整数 a i a_i ai ,组成了最初的序列,第三行为一个整数 m m m ,表示 n n n 个IQ测试询问的序列,每个序列两行,第一行给出长度 L ( 1 < = L < = n ) L(1<=L<=n) L(1<=L<=n) ,然后下一行为 L L L 个由空格分开的整数 b i b_i bi 。
输出
共 m m m 行,如果询问的序列确实是由最初的序列删除一些数得到,就输出TAK,否则输出NIE。
样例输入
7
1 5 4 5 7 8 6
4
5
1 5 5 8 6
3
2 2 2
3
5 7 8
4
1 5 7 4
样例输出
TAK
NIE
TAK
NIE
数据范围
对于
30
30%
30 的数据:
n
<
=
1000
,
m
<
=
1000
n<=1000,m<=1000
n<=1000,m<=1000
对于
100
100%
100 的数据:
1
<
=
a
i
,
b
i
<
=
1000000
,
Σ
L
<
=
1000000
,
n
,
m
<
=
1000000
1<=a_i,b_i<=1000000,ΣL<=1000000,n,m<=1000000
1<=ai,bi<=1000000,ΣL<=1000000,n,m<=1000000
思路
这道题我们要用二分来做。
我们就正常的的一个一个找,但是每一个配对的时候就二分找到下一个,就可以了。
代码
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int n, x[1000001], m, l, tail, pl;
vector<int>a[1000001];
bool yes;
int read() {//快读
int an = 0;
char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {
an = an * 10 + c - 48;
c = getchar();
}
return an;
}
int find(int xx, int yy, int tail) {
int l = -1, r = yy;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (a[xx][mid] <= tail) l = mid;
else r = mid;
}
return r;
}
int main() {
// freopen("test.in", "r", stdin);
// freopen("test.out", "w", stdout);
n = read();//读入
for (int i = 1; i <= n; i++) {
x[1] = read();//读入
a[x[1]].push_back(i);//插入队列
}
m = read();//读入
for (int i = 1; i <= m; i++) {
yes = 1;//初始化
tail = 0;
l = read();//读入
for (int j = 1; j <= l; j++)
x[j] = read();//读入
for (int j = 1; j <= l && yes; j++) {
if (a[x[j]].empty()) {//已经全部清完了
yes = 0;
break;
}
pl = find(x[j], a[x[j]].size(), tail);//找到下一个匹配的点
if (pl == a[x[j]].size()) {//超过了整个数组(没有答案)
yes = 0;
break;
}
tail = a[x[j]][pl];//重新设置尾部
}
if (yes) {//可以
putchar('T');
putchar('A');
putchar('K');
}
else {//不可以
putchar('N');
putchar('I');
putchar('E');
}
putchar('\n');
}
// fclose(stdin);
// fclose(stdout);
return 0;
}