bzoj2083 POI2010 Intelligence Test

bzoj2083 Intelligence Test

题目描述

One of the tasks in the Byteotian Intelligence Test (BIT) is to cross out numbers from an initial sequence in such a way that leaves as a result certain given sequences.

Byteasar longs to become the IQ Master of Byteotia, but he is no good in this kind of tasks.

But since practice makes perfect, he intends to practise a lot.

So much in fact that he asks you to write a program that will facilitate the training by verifying his answers quickly.

给定一个数串,和m个小数串,问这些小串都是不是大数字串的子序列

输入格式:

The first line of the standard input contains one integer ().

The second line holds integers ( for ), separated by single spaces, that constitute the initial sequence of the test.

The third line of the input holds one integer .

The following lines describe the sequences to be obtained by crossing out numbers from the initial sequence.

Each sequence's description takes two successive lines.

输出格式:

Your program should print out lines to the standard output.

The -th line (for ) should hold one word, "TAK" (yes in Polish) if the -th input sequence can be obtained by crossing out (i.e., removing) some, not necessarily contiguous, numbers from the initial sequence, or "NIE" (no in Polish) otherwise. Mind you, only the words should be printed, no quotation marks. Of course, the order of the numbers left after crossing out is important, as can be seen in the example.

题目大意:这道题就是给我们一个原始序列A,然后给我们多组询问,每一个询问包含一个序列B,问这个序列是不是原始序列经过删除一些数后得到的序列.

这道题今天省选模拟考了这道原题,以前看到过,然而还没有去做,真是遗憾.说实话这道题也不是很难.网上有多种做法,有用倍增的,也有用链表的,也有用二分的.然而前两种由于自己太弱不太会打.所以我就用了二分了.

让我们考虑30分~50分解法,我们可以枚举每一个B[i],然后再在A中找与之对应的数,记录下找到的在A上的位置pos,再接着在pos后面寻找与之对应的数.这么做大部分人都能想到,但显然会超时.于是我们想到了一种比较快捷的枚举方案:二分!

由于我们要枚举的数的位置是单调的,于是我们可以考虑二分B[i]在A中出现的位置,于是我们就有了一个大概的解法.我们用一个nxt数组存下每一个数K在A中出现的各个位置,用vector比较方便.之后我们将当前在A中搜索到的位置用一个变量pos存下.我们再枚举每一个B[i],然后在A中二分枚举B[i]出现的位置,优先往左边.如果无解的话,则返回值ret不变,那么就好判断了.

代码如下:

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

static const int maxm=1e6+10;

vector<int>nxt[maxm];
int A[maxm],B[maxm];
int n,m,Q;

int solve(int num,int pos){
    int l=0;int r=nxt[num].size()-1;int ret=n+1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(nxt[num][mid]>pos)ret=mid,r=mid-1;
        else l=mid+1;
    }
    return (ret==n+1?ret:nxt[num][ret]);
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&A[i]);
        nxt[A[i]].push_back(i);
    }
    scanf("%d",&Q);

    while(Q--){
        scanf("%d",&m);
        for(int i=1;i<=m;i++)scanf("%d",&B[i]);
        int pos=0;int f=1;int i=1;
        for(int i=1;i<=m;i++){
            pos=solve(B[i],pos);
            if(pos>n){f=0;break;}
        }
        if(f)puts("TAK");
        else puts("NIE");
    }

    return 0;
}

由于这题是权限题,我就无法贴上bzoj的链接喽,不过洛谷似乎有这道题,我就贴上这个吧:点我进入AC通道

转载于:https://www.cnblogs.com/Exbilar/p/6686746.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值