题意
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
");
continue;
}
set<int>::iterator it = s[id].lower_bound(x);
if(it!=s[id].end()&&*it<=y-k+1)printf("No
");
else printf("Yes
");
}
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
");
continue;
}
int ans = ck(root[x-1],root[y-k+1],1,ntot,id);
if(ans>0)printf("No
");
else printf("Yes
");
}
return 0;
}