COJ574 数字序列

 

试题描述
 
霸中智力测试机构的一项工作就是按照一定的规则删除一个序列的数字,得到一个确定的数列。陈思同学很渴望成为霸中智力测试机构的主管,但是他在这个工作上做的并不好,俗话说熟能生巧,他打算做很多练习,所以他希望你写一个程序来快速判断他的答案是否正确。
输入
第一行为一个整数m(1<=m<=1000000),
第二行包括m个用空格分开的整数ai(1<=ai<=1000000),组成了最初的序列,
第三行为一个整数n(1<=n<=1000000),表示n个陈思经过一系列删除得到的序列,每个序列两行,第一行给出长度L(1<=L<=m),然后下一行为L个由空格分开的整数bi(1<=bi<=1000000)。
输出
共n行,如果陈思的序列确实是由最初的序列删除一些数得到,就输出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
其他说明
二分2083

对每个权值建立位置的集合,如果用vector要写二分,如果用平衡树就直接lower_bound了。

vector,用now表示当前位置+1,下同(3979ms)

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1000010;
vector<int> T[maxn];
int main() {
    int n=read();
    rep(1,n) T[read()].push_back(i);
    int m=read();
    while(m--) {
        int k=read(),now=1,ok=1;
        rep(1,k) {
            int v=read();
            if(!T[v].size()||T[v][T[v].size()-1]<now) ok=0;
            else {
                int l=0,r=T[v].size()-1,mid;
                while(l<r) if(T[v][mid=l+r>>1]<now) l=mid+1; else r=mid;
                now=T[v][l]+1;
            }
        }
        if(ok) puts("TAK");
        else puts("NIE");
    }
    return 0;
}
View Code

偷懒用set结果T飞了(TLE)

#include<cstdio>
#include<cctype>
#include<set>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1000010;
set<int> T[maxn];
set<int>::iterator it;
int main() {
    int n=read();
    rep(1,n) T[read()].insert(i);
    int m=read();
    while(m--) {
        int k=read(),now=1,ok=1;
        rep(1,k) {
            int v=read();
            if(!T[v].size()) ok=0;
            else {
                it=T[v].lower_bound(now);
                if(it==T[v].end()) ok=0;
                else now=(*it)+1;
            }
        }
        if(ok) puts("TAK");
        else puts("NIE");
    }
    return 0;
}
View Code

STL太慢了,我们可以写一个数组,以权值为第一关键字,以位置为第二关键字排序,然后再上面继续二分。(827ms)

我竟然又WA了一发,越来越感觉要直播了。

#include<cstdio>
#include<cctype>
#include<set>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1000010;
struct Arr {
    int p,v;
    bool operator < (const Arr& ths) const {
        if(v!=ths.v) return v<ths.v;
        return p<ths.p;
    }
}A[maxn];
int L[maxn],R[maxn];
int main() {
    int n=read();
    rep(1,n) A[A[i].p=i].v=read();
    sort(A+1,A+n+1);
    int cur=1;
    rep(1,1000000) {
        if(A[cur].v!=i) continue;
        L[i]=cur;while(A[cur+1].v==i) cur++;R[i]=cur++;
    }
    int m=read();
    while(m--) {
        int k=read(),now=1,ok=1;
        rep(1,k) {
            int v=read();if(!L[v]||A[R[v]].p<now) ok=0;
            if(!ok) continue;
            int l=L[v],r=R[v],mid;
            while(l<r) if(A[mid=l+r>>1].p<now) l=mid+1; else r=mid;
            now=A[l].p+1;
        }
        if(ok) puts("TAK");
        else puts("NIE");
    }
    return 0;
}
View Code

 

posted @ 2015-07-08 16:32  wzj_is_a_juruo  阅读(200)  评论(0编辑  收藏  举报