BZOJ3207 花神的嘲讽计划Ⅰ
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3207
这题真正的数据范围:[在dicuss里有原作者发的消息]
100%的数据:1<=N<=100000;1<=M<=100000;y-x+1<=N;K<=y-x+1&K<=20;x<=y;
题中所有数据不超过2*10^9;保证方案序列的每个数字<=N
[分析]
首先这是一个判断子串是否在区间内存在的问题,像这种东西就经常想到字符串Hash...然后区间的话就会想到是不是对字符串Hash前缀和处理一下...可区间万一很长而且子串只是在这一段中的某个部分怎么办?
[好了上面都是在废话...是笨拙的笔者在看题后的错想]
注意到这题固定了询问的长度k,这就让我们想到将连续的k个作为一个元素[这当然是Hash啦]的想法,也就是说现在第i个元素表示[i...i+K-1]这段区间的Hash值。
然后在询问的时候只需要判断这个区间内是否存在这个节点就好了...
区间内查询数值是否存在...感觉和静态找区间第k小的数字感觉很像诶 [因为都是线段树当桶用的缘故吧...不过这里桶中的元素是一段区间的Hash值咯,而且判断的是在某个节点上这个区间内是否有值]
所以用的是主席树咯...
[建议]
1.推荐使用自然上溢法开unsigned long long [Hash题都比较虚,这题自然上溢很好打而且重要的是经过验证是可以A的!]
2.推荐将Hash值离散化处理,这样空间上就比较划算,速度也会更快。但是离散化注意就是在查询的时候还要判一下这个片段有没有出现过...
3.数组大小建议自己看着办...这题我RE+超空间几次...
最后上代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int in(){ int x=0;char ch=getchar(); while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } const int maxn=200010; typedef unsigned long long ll; struct Node{ int l,r,sz; }s[maxn*20]; int n,m,K,mod; int key,tot,Sz,cnt; int a[maxn],rt[maxn]; ll sum[maxn],num[maxn],b[maxn],T[maxn],p_k; inline int Find_Hash(ll x){ int l=1,r=Sz,mid; while(l<=r){ mid=(l+r)>>1; if(x>T[mid]) l=mid+1; else r=mid-1; } if(T[l]==x) return l; return -1; } void update(int last,int l,int r,int &rt){ rt=++cnt;s[rt]=s[last],s[rt].sz++; if(l==r) return; int mid=(l+r)>>1; if(key<=mid) update(s[last].l,l,mid,s[rt].l); else update(s[last].r,mid+1,r,s[rt].r); } bool query(int l,int r,int x,int y){ if(l==r) return true; int mid=(l+r)>>1,Sum=s[s[y].l].sz-s[s[x].l].sz; if(key<=mid){ if(Sum) return query(l,mid,s[x].l,s[y].l); else return false; } else{ Sum=s[s[y].r].sz-s[s[x].r].sz; if(Sum) return query(mid+1,r,s[x].r,s[y].r); else return false; } } int main(){ #ifndef ONLINE_JUDGE freopen("3207.in","r",stdin); freopen("3207.out","w",stdout); #endif n=in();m=in();K=in();mod=n+1; for(int i=1;i<=n;i++) a[i]=in(),sum[i]=sum[i-1]*mod+a[i]; p_k=1; for(int i=1;i<=K;i++) p_k=p_k*mod; for(int i=K;i<=n;i++) tot++,num[tot]=sum[i]-sum[i-K]*p_k,b[tot]=num[tot]; sort(num+1,num+tot+1); T[++Sz]=num[1]; for(int i=2;i<=tot;i++) if(num[i]!=num[i-1]) T[++Sz]=num[i]; for(int i=1;i<=tot;i++){ key=Find_Hash(b[i]); update(rt[i-1],1,Sz,rt[i]); } int L,R,X; ll code; while(m--){ L=in();R=in();code=0; for(int i=1;i<=K;i++) X=in(),code=code*mod+X; key=Find_Hash(code); if(key<0) puts("Yes"); else if(query(1,Sz,rt[L-1],rt[R-K+1])) puts("No"); else puts("Yes"); } return 0; }