ssoj1588Intelligence test(链表+二分)

来源:互联网 发布:达观数据公司总部 编辑:程序博客网 时间:2024/05/14 12:03

题目描述

霸中智力测试机构的一项工作就是按照一定的规则删除一个序列的数字,得到一个确定的数列。

Lyx很渴望成为霸中智力测试机构的主管,但是他在这个工作上做的并不好,俗话说熟能生巧,

他打算做很多练习,所以他希望你写一个程序来快速判断他的答案是否正确。

输入

第一行为一个整数m(1<=m<=1000000)

第二行包括m个用空格分开的整数ai(1<=ai<=1000000),组成了最初的序列,

第三行为一个整数n(1<=n<=1000000),表示n个Lyx经过一系列删除得到的序列,

               每个序列两行,第一行给出长度L(1<=L<=m),然后下一行为L个由空格分开的整数bi(1<=bi<=1000000)。

输出

共n行,如果Lyx的序列确实是由最初的序列删除一些数得到,就输出TAK,否则输出NIE。

样例输入

71 5 4 5 7 8 6451 5 5 8 632 2 235 7 841 5 7 4

样例输出

TAKNIETAKNIE


#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>#include <cctype>using namespace std;const int maxn=1000006;int m,n,a[maxn],b[maxn],fst[maxn],nxt[maxn],h[maxn],t[maxn],pos[maxn];inline int get(){    char c;while(!isdigit(c=getchar()));    int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;    return v;}inline int work(int x,int lim){    int l=h[x],r=t[x];    if(pos[r]<lim || l>r)return 0;    while(l<r){        int mid=(l+r)>>1;        if(pos[mid]<lim)l=mid+1;else r=mid;    }    return pos[l];}int main(){    m=get();memset(fst,0,sizeof(fst));memset(nxt,0,sizeof(nxt));    for(int i=1;i<=m;++i)a[i]=get();    for(int i=m;i>=1;--i)nxt[i]=fst[a[i]],fst[a[i]]=i;    for(int i=1;i<=maxn;++i){        h[i]=t[i-1]+1;t[i]=t[i-1];        for(int j=fst[i];j;j=nxt[j])pos[++t[i]]=j;    }    n=get();    for(int i=1;i<=n;++i){        int l=get();        int lim=0;bool flag=1;        for(int j=1;j<=l;++j){            int x=get();            if(flag){                int pos=work(x,lim);                if(!pos)flag=0;                lim=pos+1;            }        }        if(flag)printf("TAK\n");        else printf("NIE\n");    }    return 0;}


思路:很快想到用链表做,但是超时了。于是记录下每个数出现的位置,对于询问的数当然取越前面越好,发现每个数出现的位置是递增的,用二分。


注意:(1)有些时候还要再想深一点。(2)一个细节lim=当前位置+1





0 0
原创粉丝点击