HDU - 5172 GTY's gay friends
题意:n个数m个查询,问[l,r]中的数是否为1到r-l+1的一个排列。
做法1:
hash一下,对于[1...n],每个数都随机分配一个hash值,一个集合的hash值为元素异或和。预处理出[1...n]的hash值及其前缀的hash,然后就可以O(1)查询了
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<map> #include<ctime> #define eps (1e-8) using namespace std; typedef long long ll; unsigned long long ra[1000005],a[1000005],ha[1000005]; int n,m,t,p; int main() { srand(time(NULL)); a[0] = ha[0] = 0; for(int i=1; i<=1000000; i++) { ra[i] = rand()*rand(); ha[i] = ha[i-1]^ra[i]; } while(~scanf("%d%d",&n,&m)) { for(int i=1; i<=n; i++) { scanf("%d",&t); a[i] = ra[t]; a[i]^=a[i-1]; } for(int i=1; i<=m; i++) { scanf("%d%d",&t,&p); puts((ha[p-t+1]==(a[p]^a[t-1])?"YES":"NO")); } } return 0; }
做法二:线段树
若(l,r)中的数为1 ~ r-l+1中的一个排列,则必须满足:
1、(l,r)中的数之和为len*(len+1)/2,其中len = r-l+1。
2、区间内的数字各不相同,即用线段树维护位置i上的数上次出现的位置的最大值。只要区间内所有的数上次出现的位置last[i] < l,则区间内的数各不相同。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <math.h> using namespace std; typedef long long LL; const int N = 1000005; int pre[N],now[N]; LL sum[N]; struct Tree{ int MAX_ID; }tree[N<<2]; int MAX_ID; void PushUp(int idx){ tree[idx].MAX_ID = max(tree[idx<<1].MAX_ID,tree[idx<<1|1].MAX_ID); } void build(int l,int r,int idx){ if(l==r){ tree[idx].MAX_ID = pre[l]; return; } int mid = (l+r)>>1; build(l,mid,idx<<1); build(mid+1,r,idx<<1|1); PushUp(idx); } void query(int l,int r,int L,int R,int idx){ if(l >= L&& r <= R){ MAX_ID = max(MAX_ID,tree[idx].MAX_ID); return; } int mid = (l+r)>>1; if(mid>=L) query(l,mid,L,R,idx<<1); if(mid<R) query(mid+1,r,L,R,idx<<1|1); } int main() { int n,k; while(scanf("%d%d",&n,&k)!=EOF){ memset(now,0,sizeof(now)); sum[0] = 0; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); sum[i] = sum[i-1]+x; pre[i] = now[x]; now[x] = i; } build(1,n,1); while(k--){ int l,r; scanf("%d%d",&l,&r); LL len = r-l+1; LL S = (len+1)*(len)/2; if(sum[r]-sum[l-1]!=S){ printf("NO\n"); continue; } MAX_ID = -1; query(1,n,l,r,1); if(MAX_ID<l) printf("YES\n"); else printf("NO\n"); } } return 0; }