把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3500 [POI2010]TES-Intelligence Test

题面传送门
题目描述:给定一个标准串\(a\),再给出很多串\(b\),问\(b\)是不是\(a\)的子序列。
方法一:最长公共子序列(太无脑了)
方法二:首尾一个一个对过去比较
方法三:链表
对于每个\(a_i\),令\(s_i\)指向下一个与\(a_i\)值相同的位置。
我们在匹配子序列时,对于一个\(b_i\),原本我们要一个个去比较,现在我们只要\(O(1)\)就可以指向所对应的元素。并查询,如果不满足上升的要求,便往后一个。直到找到第一个满足上升要求的,并使其与\(b_i\)匹配。这个贪心的思路大家一想就通。
代码实现:

#include<cstdio>
#include<cstring>
using namespace std;
int f[1000039],a[1000039],b[1000039],s[1000039],x[1000039],y,z,n,m,head,k,h[1000039],flag;
int main() {
    register int i;
    scanf("%d",&n);
    for(i=1; i<=n; i++) {
        scanf("%d",&a[i]);
        if(!f[a[i]]) f[a[i]]=i;
        if(!s[a[i]]) s[a[i]]=i;
        else b[s[a[i]]]=i,s[a[i]]=i;
    }
    for(i=1; i<=1000000; i++) h[i]=f[i];
    scanf("%d",&m);
    while(m--) {
        head=flag=0;
        scanf("%d",&k);
        for(i=1; i<=k; i++)scanf("%d",&x[i]);
        for(i=1; i<=k; i++) {
            while(h[x[i]]&&h[x[i]]<head) h[x[i]]=b[h[x[i]]];
            if(!h[x[i]]) {flag=1;break;} 
            else head=h[x[i]],h[x[i]]=b[h[x[i]]];
        }
        for(i=1; i<=k; i++) h[x[i]]=f[x[i]];
        if(flag) printf("NIE\n");
        else printf("TAK\n");
    }
}

本来以为能\(AC\)的,但只有\(78\)分,不愧评上了蓝题。我们把这个模型再抽象,抽象到有\(a_i\)个队列,里面的元素在逐个检查。这可以用\(vector\)来实现。不过我们可以在入队时使其具有单调性,这样到后面就可以二分查找第一个大于这个元素的值。考试时以为第一种方法如果数据随机和二分复杂度差不多,所以没打二分,也觉得二分麻烦。考试后打了一下,没想到比解法三还好打。
代码实现:

#include<cstdio>
#include<vector>
using namespace std;
int n,m,a[1000039],k,x[1000039],l,r,mid,head,h[1000039],flag;
vector<int> f[1000039];
inline void read(int &x){
    x=0;char s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9')x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
int main(){
    register int i;
    scanf("%d",&n);
    for(i=1;i<=n;i++) read(a[i]),f[a[i]].push_back(i);
    scanf("%d",&m);
    while(m--){
        flag=head=0;
        read(k);
        for(i=1;i<=k;i++) read(x[i]);
        for(i=1;i<=k;i++){
            l=-1;r=f[x[i]].size();
            //printf("%d\n",r);
            if(!r) {flag=1;break;}
            while(l+1<r){
                mid=(l+r)>>1;
                if(f[x[i]][mid]>head) r=mid;
                else l=mid;
            }
            //printf("%d\n",r);
            if(r==f[x[i]].size()) {flag=1;break;}
            head=f[x[i]][r],h[x[i]]=r+1;
        }
        if(flag) printf("NIE\n");
        else printf("TAK\n");
    }
}

做这道题要有对二分足够的认识---\(wcx\)

posted @ 2020-03-27 09:20  275307894a  阅读(41)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end