HDU

题目链接

题意: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
");
                continue;
            }
            MAX_ID = -1;
            query(1,n,l,r,1);
            if(MAX_ID<l) printf("YES
");
            else printf("NO
");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/7257524.html