BZOJ_3207_花神的嘲讽计划1_(Hash+主席树)

描述



http://www.lydsy.com/JudgeOnline/problem.php?id=3207

给出一个长度为\(n\)的串,以及\(m\)个长度为\(k\)的串,求每个长度为\(k\)的串在原串\([x,y]\)区间是否出现过.

分析



这道题要求对比长度为\(k\)的串,于是我们把这些串的Hash值都算出来,问题就转化成了求\([x,y]\)的区间中是否出现过某Hash值.

求区间中某一个值出现了多少次,可以用主席树.

p.s.

1.学习了主席树指针的写法,比数组慢好多啊...看来有必要去学一学平衡树的数组写法...不过好处是不用自己算空间...

2.这道题自己算空间的话会MLE,所以卡着空间限制就好,估计数据比较小,可以过.

数组:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int maxn=200000+5,X=27;
 5 typedef unsigned long long ull;
 6 const ull INF=~0ull;
 7 int n,m,k,cnt;
 8 int a[maxn],rt[maxn];
 9 ull s[maxn],x=1;
10 struct node{ int l,r,s; }t[maxn*50];
11 inline int read(int &x){ x=0;int k=1;char c;for(c=getchar();c<‘0‘||c>‘9‘;c=getchar())if(c==‘-‘)k=-1;for(;c>=‘0‘&&c<=‘9‘;c=getchar())x=x*10+c-‘0‘;return x*=k; }
12 void update(ull l,ull r,int &pos,ull d){
13     t[++cnt]=t[pos]; pos=cnt; t[pos].s++;
14     if(l==r) return;
15     ull mid=l+(r-l)/2;
16     if(d<=mid) update(l,mid,t[pos].l,d);
17     else update(mid+1,r,t[pos].r,d);
18 }
19 bool query(int x,int y,ull l,ull r,ull d){
20     if(t[y].s-t[x].s==0) return false;
21     if(l==r) return true;
22     ull mid=l+(r-l)/2;
23     if(d<=mid) return query(t[x].l,t[y].l,l,mid,d);
24     else return query(t[x].r,t[y].r,mid+1,r,d);
25 }
26 int main(){
27     read(n); read(m); read(k);
28     for(int i=1;i<=n;i++){
29         read(a[i]);
30         s[i]=s[i-1]*X+(ull)a[i];
31     }
32     for(int i=1;i<=k;i++) x*=X;
33     for(int i=k;i<=n;i++) rt[i]=rt[i-1], update(0ull,INF,rt[i],s[i]-s[i-k]*x);
34     for(int i=1;i<=m;i++){
35         ull hash=0; bool ans;
36         int l,r; read(l); read(r);
37         for(int j=1,t;j<=k;j++)  hash=hash*X+read(t);
38         if(r+1-l<k) ans=false;
39         else ans=query(rt[l+k-2],rt[r],0ull,INF,hash);
40         ans?puts("No"):puts("Yes");
41     }
42     return 0;
43 }

指针:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int maxn=200000+5,X=27;
 5 typedef unsigned long long ull;
 6 const ull INF=~0ull;
 7 int n,m,k,cnt;
 8 int a[maxn];
 9 ull s[maxn],x=1;
10 struct node{
11     node* l,* r; int s;
12     node(){}
13     node(node *l,node* r,int s):l(l),r(r),s(s){}
14 }* rt[maxn],* null;
15 inline int read(int &x){ x=0;int k=1;char c;for(c=getchar();c<‘0‘||c>‘9‘;c=getchar())if(c==‘-‘)k=-1;for(;c>=‘0‘&&c<=‘9‘;c=getchar())x=x*10+c-‘0‘;return x*=k; }
16 node* update(node* t,ull l,ull r,ull d){
17     if(l==r) return new node(null,null,t->s+1);
18     ull mid=l+(r-l)/2;
19     if(d<=mid) return new node(update(t->l,l,mid,d),t->r,t->s+1);
20     else return new node(t->l,update(t->r,mid+1,r,d),t->s+1);
21 }
22 bool query(node* x,node* y,ull l,ull r,ull d){
23     if(y->s-x->s==0) return false;
24     if(l==r) return true;
25     ull mid=l+(r-l)/2;
26     if(d<=mid) return query(x->l,y->l,l,mid,d);
27     else return query(x->r,y->r,mid+1,r,d);
28 }
29 int main(){
30     read(n); read(m); read(k);
31     null=new node;
32     null->l=null, null->r=null, null->s=0;
33     for(int i=1;i<=n;i++){
34         read(a[i]);
35         s[i]=s[i-1]*X+(ull)a[i];
36     }
37     for(int i=1;i<=k;i++) x*=X;
38     rt[k-1]=new node(null,null,0);
39     for(int i=k;i<=n;i++) rt[i]=update(rt[i-1],0ull,INF,s[i]-s[i-k]*x);
40     for(int i=1;i<=m;i++){
41         ull hash=0; bool ans;
42         int l,r; read(l); read(r);
43         for(int j=1,t;j<=k;j++)  hash=hash*X+read(t);
44         if(r+1-l<k) ans=false;
45         else ans=query(rt[l+k-2],rt[r],0ull,INF,hash);
46         ans?puts("No"):puts("Yes");
47     }
48     return 0;
49 }

时间: 2024-09-27 20:24:03

BZOJ_3207_花神的嘲讽计划1_(Hash+主席树)的相关文章

BZOJ_3207_花神的嘲讽计划Ⅰ_哈希+主席树

Description 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程序怎么跑这么快!J要逆袭了!” …… 描述 这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听.以下是部分摘录: 1. “J你在讲什么!” “我在讲XXX!” “哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!” “……” 2. “J你XXX讲过了没?” “……” “那个都不讲你就讲这个了?哎你傻不傻的!” “……”

[BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】

题目链接:BZOJ - 3207 题目分析 先使用Hash,把每个长度为 k 的序列转为一个整数,然后题目就转化为了询问某个区间内有没有整数 x . 这一步可以使用可持久化线段树来做,虽然感觉可以有更简单的做法,但是我没有什么想法... 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #inclu

BZOJ 3207 花神的嘲讽计划I Hash+可持久化线段树

题目大意:给定一个数字串,多次求某个区间内有没有一个长度为k的子串 首先对字符串进行哈希 然后问题就转化成了求一个区间内有没有某个数 可持久化线段树即可 其实我觉得划分树会更快一些 可以写写 ※注意事项: 1.n<=200000 我找不到数据范围是眼科大夫去找老阎的关系? 2.哈希值用unsigned long long 铁则 unsigned int 会被卡掉 3.线段树那里直接x+y>>1会爆unsigned long long 转换一下 x+y>>1=(x>>

[bzoj3207]花神的嘲讽计划Ⅰ[可持久化线段树,hash]

将每k个数字求一个哈希值,存入可持久化线段树,直接查询即可 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 9 using namespace std; 10 11 #define

【BZOJ3207】花神的嘲讽计划Ⅰ Hash+主席树

[BZOJ3207]花神的嘲讽计划Ⅰ Description 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程序怎么跑这么快!J要逆袭了!” …… 描述 这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听.以下是部分摘录: 1. “J你在讲什么!” “我在讲XXX!” “哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!” “……” 2. “J你XXX讲过了没?” “……” “那个都不讲你就

BZOJ 3207: 花神的嘲讽计划Ⅰ( hash + 可持久化线段树 )

O(NK)暴力搞出所有子串的哈希值, 然后就对哈希值离散化建权值线段树, 就是主席树的经典做法了.总时间复杂度O(NK+(N+Q)logN) -------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespa

【BZOJ3207】花神的嘲讽计划I 可持久化线段树/莫队

看到题目就可以想到hash 然后很自然的联想到可持久化权值线段树 WA:base取了偶数 这道题还可以用莫队做,比线段树快一些 可持久化线段树: 1 #include<bits/stdc++.h> 2 #define ll long long 3 #define uint unsigned int 4 #define ull unsigned long long 5 #define inf 4294967295 6 #define N 100005 7 #define M 100005 8 #

【BZOJ】【1046】【HAOI2007】花神的嘲讽计划 I

字符串Hash+可持久化线段树 好神奇的转化…… 蒟蒻一开始还去想AC自动机去了……然而由于a[i]的范围是小于等于n,怎么也想不出一个时间复杂度合理的方法 膜拜了题解0.0原来是字符串Hash! 首先每个询问的长度都是固定的!K!那么我们就可以看作一个长度为K的数!然后就可以利用字符串Hash将一个长度为n的数列转化成一个长度为n-k+1的数列!查询一个特定的序列在一个区间中是否出现过,就变成了在一段区间中,某个数是否出现过!然后就可以用可持久化线段树来维护了…… 长度为K这个条件好神啊……居

【bzoj3207】花神的嘲讽计划Ⅰ Hash+STL-map+莫队算法

题目描述 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程序怎么跑这么快!J要逆袭了!” …… 描述 这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听.以下是部分摘录: 1. “J你在讲什么!” “我在讲XXX!” “哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!” “……” 2. “J你XXX讲过了没?” “……” “那个都不讲你就讲这个了?哎你傻不傻的!” “……” DJ对这种情景