题目传送门
。
解法:
然而我不是很清楚hash为啥要开long long
int 不行吗。。
hash学习
学了一发hash。
这个东西有点狗啊。
有几率重复啊。。
不过很小(欧洲人)
然后主席树维护一下每个hash。
离散化一下。
因为长度为k。
那么把进来的串变成hash。
然后在区间找这个hash是否出现过。。
然后就本机AC提交WA了。
改了longlong才过。
难道int就使得hash重复了吗。
代码实现:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef unsigned long long ll;
struct node {int lc,rc,c;}t[5100000];int cnt,rt[1100000];
void build(int &u,int l,int r,int p) {
if(u==0)u=++cnt;t[u].c++;
if(l==r)return ;int mid=(l+r)/2ll;
if(p<=mid)build(t[u].lc,l,mid,p);
else build(t[u].rc,mid+1,r,p);
}
void Merge(int &u1,int u2) {
if(u1==0) {u1=u2;return ;}if(u2==0)return ;
t[u1].c+=t[u2].c;
Merge(t[u1].lc,t[u2].lc);
Merge(t[u1].rc,t[u2].rc);
}
ll base=222;
ll a[110000];int n,m,K;
struct edge {ll x;int id;}Hash[1100000];
bool cmp(edge n1,edge n2) {return n1.x<n2.x;}
int pos(ll x) {
int l=1,r=n-K+1,mid,ans=0;
while(l<=r) {
mid=(l+r)/2;
if(Hash[mid].x<=x) {
if(Hash[mid].x==x)ans=mid;
l=mid+1;
}else r=mid-1;
}return ans;
}
bool find(int u1,int u2,int l,int r,int x) {
if(t[u1].c-t[u2].c==0)return false;
if(l==r)return true;int mid=(l+r)/2;
if(x<=mid)return find(t[u1].lc,t[u2].lc,l,mid,x);
else return find(t[u1].rc,t[u2].rc,mid+1,r,x);
}int s[1100000];
ll hash() {
ll ans=0;
for(int i=1;i<=K;i++)ans=ans*base+a[i];
return ans;
}
int main() {
//freopen("3027.in","r",stdin);freopen("3027.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);cnt=0;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n-K+1;i++) {
Hash[i].x=0;Hash[i].id=i;
for(int j=i;j<=i+K-1;j++)Hash[i].x=Hash[i].x*base+a[j];
}sort(Hash+1,Hash+1+n-K+1,cmp);
int tot=0;
for(int i=1;i<=n-K+1;i++) {
if(Hash[i].x!=Hash[i-1].x)tot++;s[i]=tot;
build(rt[Hash[i].id],1,n-K+1,tot);
}
for(int i=1;i<=n-K+1;i++)Merge(rt[i],rt[i-1]);
while(m--) {
int l,r;scanf("%d%d",&l,&r);
for(int i=1;i<=K;i++)scanf("%lld",&a[i]);
int X=pos(hash());
if(X==0) {printf("Yes\n");continue;}
if(find(rt[r-K+1],rt[l-1],1,n-K+1,s[X])==true)printf("No\n");
else printf("Yes\n");
}
return 0;
}