首页 > 其他 > 详细

BZOJ 3207 花神的嘲讽计划I (hash)

时间:2020-03-30 09:15:33      阅读:61      评论:0      收藏:0      [点我收藏+]

题意

1e5的数组,1e5的询问,每次给你的长度相同(<=20)的一组数,和(l,r),问你这组数是不是(l,r)内的子串

思路

思路还是蛮好想的..
hash出(i,i+k-1)的子串,然后每次在主席树内查询,但是不知道为什么一直wa..自己造了很多组数据都没抛出错误..(找到错误了是hash模数太蠢)
网上看到stl过的,发现自己撒比了
先将数组里hash值一样的扔到set里,每次只需要将询问串的hash在set里lower_bound(l),判断它存在并且<=r-k+1即可

似乎可以总结一下:判断某区间是否存在一个值,set里二分就行?

代码

值域里二分:

int t;
int n,m,k;
ll a[maxn];
ull pre[maxn];
ull po[maxn];
ll gt(int l, int r){
    return (pre[r]-pre[l-1]*po[r-l+1]);
}
vector<ll>v;
int getid(ll x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
set<int>s[maxn];
int main() {
    po[0]=1;
    scanf("%d %d %d", &n, &m, &k);
    for(int i = 1; i <= n; i++)po[i]=po[i-1]*1337;
    for(int i = 1; i <= n; i++){
        scanf("%lld", &a[i]);
        pre[i]=pre[i-1]*1337+a[i];
    }
    for(int i = 1; i+k-1<=n; i++){
        v.pb(gt(i,i+k-1));
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    int ntot = v.size();
    for(int i = 1; i+k-1<=n; i++){
        a[i]=getid(gt(i,i+k-1));
        s[a[i]].insert(i);
    }
    while(m--){
        int x,y;
        ll tmp = 0;
        scanf("%d %d", &x, &y);
        for(int i = 1; i <= k; i++){
            int o;
            scanf("%d", &o);
            tmp=tmp*1337+o;
        }
        int id = getid(tmp);
        if(v[id-1]!=tmp){
            printf("Yes\n");
            continue;
        }
        set<int>::iterator it = s[id].lower_bound(x);
        if(it!=s[id].end()&&*it<=y-k+1)printf("No\n");
        else printf("Yes\n");

    }

    return 0;
}

主席树:

int t;
int n,m,k;
ll a[maxn];
ull pre[maxn];
ull po[maxn];
ull gt(int l, int r){
    return (pre[r]-pre[l-1]*po[r-l+1]);
}
vector<ull>v;
int getid(ull x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int ls[40*maxn],rs[40*maxn];
ll dat[40*maxn];
int root[maxn];
int tot;
int insert(int now, int l, int r, int x, int val){
    int p = ++tot;
    ls[p]=ls[now];rs[p]=rs[now];dat[p]=dat[now];
    if(l==r){
        dat[p]=1;return p;
    }
    int mid = l+r>>1;
    if(x<=mid)ls[p]=insert(ls[now],l,mid,x,val);
    else rs[p]=insert(rs[now],mid+1,r,x,val);
    dat[p]=dat[ls[p]]+dat[rs[p]];
    return p;
}
int ck(int x, int y, int l, int r, int k){
    int mid =l+r>>1;
    if(l==r)return dat[y]-dat[x];
    if(k<=mid){
        return ck(ls[x],ls[y],l,mid,k);
    }
    else return ck(rs[x],rs[y],mid+1,r,k);

}

int main() {
    //freopen("wrjAc.in","r",stdin);
    //freopen("wrjMy.out","w",stdout);
    scanf("%d %d %d", &n, &m, &k);
    po[0]=1;
    for(int i = 1; i <= n; i++)po[i]=po[i-1]*1337;
    for(int i = 1; i <= n; i++){
        scanf("%lld", &a[i]);
        pre[i]=pre[i-1]*1337+a[i];
    }
    for(int i = 1; i+k-1<=n; i++){
        v.pb(gt(i,i+k-1));
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    int ntot = v.size();
    for(int i = 1; i+k-1<=n; i++){
        a[i]=getid(gt(i,i+k-1));
        root[i]=insert(root[i-1],1,ntot,a[i],1);
    }
    while(m--){
        int x,y;
        ull tmp = 0;
        scanf("%d %d", &x, &y);
        for(int i = 1; i <= k; i++){
            int o;
            scanf("%d", &o);
            tmp=tmp*1337+o;
        }
        int id = getid(tmp);
        if(v[id-1]!=tmp){
            printf("Yes\n");
            continue;
        }

        int ans = ck(root[x-1],root[y-k+1],1,ntot,id);
        if(ans>0)printf("No\n");
        else printf("Yes\n");

    }
    return 0;
}

BZOJ 3207 花神的嘲讽计划I (hash)

原文:https://www.cnblogs.com/wrjlinkkkkkk/p/12596096.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!