题意:
给出一个长度为n的序列,有m个询问;
每次给出一个区间[l,r]和一个长度为K的短序列;
查询区间中是否存在这个子串;
1<=n<=100000,1<=m<=100000,1<=K<=20;
题中所有数据不超过2*10^9;保证方案序列的每个数字<=n
题解:
这题我读了好几遍没读懂,看了题解才知道这问的是查询一个固定长度的字符串是否在区间出现;
然后就是简单题了,用Hash来搞;
处理原串中所有的Hash值,然后如果[l,r]存在一个Hash值为A的子串,那么预处理的那一段中一定也有一个与其相同的元素;
利用离散化之后的可持久化线段树实现;
查询就是直接去查对应区间那个值是否存在;
时间复杂度O(nlogn),空间复杂度O(nlogn);
1A一道数据结构好愉悦啊!
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define M 5000000
#define seed 1000000007ll
using namespace std;
typedef unsigned long long ll;
int sum[M],ls[M],rs[M],tot;
int a[N],root[N],size;
ll hash[N],dis[N];
void Pushup(int no)
{
sum[no]=sum[ls[no]]+sum[rs[no]];
}
void Insert(int l,int r,int &no,int val)
{
int p=++tot;
ls[p]=ls[no],rs[p]=rs[no];
sum[p]=sum[no];
no=p;
if(l==r)
sum[no]++;
else
{
int mid=l+r>>1;
if(val<=mid)Insert(l,mid,ls[no],val);
else Insert(mid+1,r,rs[no],val);
Pushup(no);
}
}
int query(int l,int r,int nol,int nor,int val)
{
if(l==r)
{
return sum[nor]-sum[nol];
}
else
{
int mid=l+r>>1;
if(val<=mid)return query(l,mid,ls[nol],ls[nor],val);
else return query(mid+1,r,rs[nol],rs[nor],val);
}
}
int main()
{
int n,m,len,i,j,k,x,y,l,r;
ll powk,now;
scanf("%d%d%d",&n,&m,&len);
for(i=1;i<=n;i++)
{
scanf("%d",a+i);
hash[i]=hash[i-1]*seed+a[i];
}
for(i=1,powk=1;i<=len;i++)
powk*=seed;
for(i=len;i<=n;i++)
{
dis[i-len+1]=hash[i]-hash[i-len]*powk;
}
sort(dis+1,dis+n-len+1);
size=unique(dis+1,dis+n-len+1)-dis-1;
for(i=len;i<=n;i++)
{
root[i]=root[i-1];
Insert(1,size,root[i],lower_bound(dis+1,dis+size+1,hash[i]-hash[i-len]*powk)-dis);
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&l,&r);
for(j=1,now=0;j<=len;j++)
{
scanf("%d",&x);
now=now*seed+x;
}
k=lower_bound(dis+1,dis+size+1,now)-dis;
if(dis[k]!=now||query(1,size,root[l+len-2],root[r],k)==0)
puts("Yes");
else
puts("No");
}
return 0;
}