题目简述:
给你一个模式串
P
,
数据范围:
n,m≤200000
题目挺裸,想法也很裸,但需要一些注意的地方
首先匹配这种事情肯定是直接
hash
之,因为出现的串数量较大,所以用自然溢出的unsigned long long(其实根据hash killer III的经验,用双质数hash更安全)。然后以原序列的每个长为k的子串的
hash
值建主席树,查询就变成了在区间中是否存在相应数。
然后下面是关键,在求区间中点时不能用(l+r)>>1,因为加起来会炸,所以要换成(l>>1)+(r>>1)+(r&l&1)。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef double db;
int getint()
{
int f=1,g=0;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9')g=(g<<3)+(g<<1)+c-'0',c=getchar();
return f*g;
}
const int base=103;
const int maxn=200005;
const ll inf=18446744073709551615ul;
ll bin[maxn];
ll ha[maxn];
int n,m,k;
ll hash(int l,int r)
{
return ha[r]-ha[l-1]*bin[r-l+1];
}
int root[maxn];
int lc[maxn*43];
int rc[maxn*43];
int sum[maxn*43];
int tot;
#define mid ( (l>>1)+(r>>1)+(r&l&1) )
void up(int x){sum[x]=sum[lc[x]]+sum[rc[x]];}
void insert(int &x,int last,ll l,ll r,ll val)
{
if(!x)x=++tot;
sum[x]=sum[last];
if(l==r)
{
sum[x]++;
return;
}
if(val<=mid)insert(lc[x],lc[last],l,mid,val),rc[x]=rc[last];
else insert(rc[x],rc[last],mid+1,r,val),lc[x]=lc[last];
sum[x]=sum[lc[x]]+sum[rc[x]];
}
int query(int now,int last,ll l,ll r,ll val)
{
if(sum[now]-sum[last]==0)return 0;
if(l==r)
{
return sum[now]-sum[last];
}
if(val<=mid)return query(lc[now],lc[last],l,mid,val);
else return query(rc[now],rc[last],mid+1,r,val);
}
int main()
{
// freopen("taunt5.in","r",stdin);
// freopen("out5.txt","w",stdout);
n=getint();
m=getint();
k=getint();
ll temp;
bin[0]=1;
for(int i=1;i<maxn;i++)bin[i]=bin[i-1]*base;
for(int i=1;i<=n;i++)
{
temp=getint();
ha[i]=ha[i-1]*base+temp;
}
for(int i=1;i<=n-k+1;i++)
{
ll temp=hash(i,i+k-1);
insert(root[i],root[i-1],0,inf,temp);
}
for(int i=1;i<=m;i++)
{
int l=getint();
int r=getint();
r=r-k+1;
temp=0;
if(r<l)
{
puts("Yes");
continue;
}
for(int j=1;j<=k;j++)
{
temp=temp*base+getint();
}
if(query(root[r],root[l-1],0,inf,temp))
{
puts("No");
}
else
{
puts("Yes");
}
}
return 0;
}