BZOJ2083: [Poi2010]Intelligence test

给n<=1e6的序列每个数<=1e6,求m<=1e6个询问,每次问一个长度L<=n的序列是不是一开始给的序列的子序列。

贪心一波,每进来一个数就找他最早的可能位置,这样是比后面的位置要好的。一开始预处理,把每个数字的编号,按数字大小第一关键字,编号第二,放在一个表里,在表里面二分即可。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 //#include<iostream>
 6 using namespace std;
 7 
 8 int n,m;
 9 #define maxn 1000011
10 int a[maxn],ll[maxn],rr[maxn],list[maxn],cnt[maxn];
11 int main()
12 {
13     scanf("%d",&n);
14     memset(cnt,0,sizeof(cnt));
15     memset(ll,0,sizeof(ll));memset(rr,0,sizeof(rr));
16     for (int i=1;i<=n;i++) scanf("%d",&a[i]),cnt[a[i]]++;
17     int now=1,Max=1e6+1;
18     for (int i=0;i<=Max;i++) if (cnt[i]) ll[i]=rr[i]=now,now+=cnt[i];
19     for (int i=1;i<=n;i++) list[rr[a[i]]++]=i;
20 //    for (int i=1;i<=n;i++) cout<<list[i]<<' ';cout<<endl;
21     scanf("%d",&m);
22     int b,x;
23     while (m--)
24     {
25         scanf("%d",&b);
26         now=1;bool flag=1;
27         while (b--)
28         {
29 //            cout<<now<<' ';
30             scanf("%d",&x);
31             int L=ll[x],R=rr[x];
32             while (L<R)
33             {
34                 int mid=(L+R)>>1;
35                 if (list[mid]>=now) R=mid;
36                 else L=mid+1;
37             }
38             if (L==rr[x])
39             {
40                 flag=0;
41                 while (b--) scanf("%d",&x);
42                 break;
43             }
44             now=list[L]+1;
45         }//cout<<endl;
46         puts(flag?"TAK":"NIE");
47     }
48     return 0;
49 }
View Code

 

posted @ 2017-10-06 20:05  Blue233333  阅读(211)  评论(0编辑  收藏  举报