IQ测试
jzoj 5048
题目大意
给出一个序列a,然后有m个询问,每个询问给出一个序列,问这个序列是否可以由序列a删掉一些数得到的
输入样例
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%的数据:n⩽1000,m⩽1000n\leqslant 1000,m\leqslant 1000n⩽1000,m⩽1000
对于100%的数据:1⩽ai,bi⩽1000000,∑L⩽1000000,n,m⩽10000001\leqslant ai,bi\leqslant 1000000,\sum L\leqslant 1000000,n,m\leqslant 10000001⩽ai,bi⩽1000000,∑L⩽1000000,n,m⩽1000000
解题思路
数据有1000000这么大,那应该就是o(n)o(n)o(n)左右的
数据写到∑L⩽1000000\sum L\leqslant 1000000∑L⩽1000000,那他就一定有他的作用
我们把所有序列放在一起看
我们可以枚举序列a,对于每一个数
如果和某个序列的指针所指向的数字相同,那我们就把这个序列的指针指向下一位,就是当前数字已找到
如果一个序列可以按顺序在序列a中找到它的每一个数,那它就是符合的
但如果每一个序列都搜一遍的话就会TLETLETLE
我们可以用一个数组来记录指针指向某个数字的序列有哪些
代码
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n, m, w, g, a[1000010], s[1000010];
vector<int>h[1000010], b[1000010];//要用vector才能即不超时又不超内存
int main()
{scanf("%d", &n);for (int i = 1; i <= n; ++i)scanf("%d", &a[i]);scanf("%d", &m);for (int i = 1; i <= m; ++i){scanf("%d", &w);for (int j = 1; j <= w; ++j){scanf("%d", &g);b[i].push_back(g);}h[b[i].front()].push_back(i);//第一个数}for (int i = 1; i <= n; ++i){w = h[a[i]].size();//指针指向a[i]序列数for (int j = 0; j < w; ++j){g = h[a[i]][j];//第几个序列s[g]++;//指针加一if (s[g] < b[g].size()) h[b[g][s[g]]].push_back(g);//没有遍历完,再指向下一个}h[a[i]].erase(h[a[i]].begin(), h[a[i]].begin() + w);//删掉原有的}for (int i = 1; i <= m; ++i)if (s[i] >= b[i].size()) printf("TAK\n");//遍历完的else printf("NIE\n");return 0;
}