HDU 5172 GTY's gay friends HASH随机算法

传送门:点击打开链接

GTY's gay friends

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 562    Accepted Submission(s): 127


Problem Description
GTY has n gay friends. To manage them conveniently, every morning he ordered all his gay friends to stand in a line. Every gay friend has a characteristic value ai , to express how manly or how girlish he is. You, as GTY's assistant, have to answer GTY's queries. In each of GTY's queries, GTY will give you a range [l,r] . Because of GTY's strange hobbies, he wants there is a permutation [1..rl+1] in [l,r] . You need to let him know if there is such a permutation or not.
 


Input
Multi test cases (about 3) . The first line contains two integers n and m ( 1n,m1000000 ), indicating the number of GTY's gay friends and the number of GTY's queries. the second line contains n numbers seperated by spaces. The ith number ai ( 1ain ) indicates GTY's ith gay friend's characteristic value. The next m lines describe GTY's queries. In each line there are two numbers l and r seperated by spaces ( 1lrn ), indicating the query range.
 


Output
For each query, if there is a permutation [1..rl+1] in [l,r] , print 'YES', else print 'NO'.
 


Sample Input
  
  
8 5 2 1 3 4 5 2 3 1 1 3 1 1 2 2 4 8 1 5 3 2 1 1 1 1 1 1 2
 


Sample Output
  
  
YES NO YES YES YES YES NO
 


Source

题意:给出一个长度为n的数组(n<=100W).每个数都<=100W。然后m次询问,每次询问l..r区间内是否为1..r-l+1的一个排列。

思路:对每个数生成一个无符号64bit随机数。可以求得1..x的随机值的异或和(用xor[i]表示1..i的异或和)。求得a[1..n]的异或和(用sum[i]表示从a[1]到a[i]的异或和)。对于每一个询问l,r,用前缀和的思想,可以求出a[l..r]的异或和。异或满足交换律,如果这个值和xor[r-l+1]相等的话,那么这个区间内就是一个1..r-l+1的排列。

代码:

#include<cstdio>
#include<ctime>
#include<cstdlib>
#define uLL unsigned __int64
#define maxn 1000005
uLL XOR[maxn],sum[maxn],val[maxn];
inline uLL RANDuLL()
{
    uLL one=1;
    uLL RAND=(rand()+rand())*(one<<47)+(rand()+rand())*(one<<31)+(rand()+rand())*(one<<15)+(rand()+rand());
    return RAND;
}
inline int getint()
{
    int c;
    while (c = getchar(), c<'0' || '9'<c);
    int res = c - 48;
    while (c = getchar(), '0' <= c&&c <= '9') res = (res << 3) + res + res + c - 48;
    return res;
}
int main()
{
    srand(time(NULL));
    XOR[0]=0;
    for(int i=1;i<maxn;i++)
    {
        val[i]=RANDuLL();
        XOR[i]=XOR[i-1]^val[i];
    }
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            int x;
            x=getint();
            sum[i]=val[x]^sum[i-1];
        }
        while(m--)
        {
            int l,r;
            l=getint();
            r=getint();
            if(XOR[r-l+1]==(sum[r]^sum[l-1])) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}

极度优化的线段树也是能过的。姿势最重要

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef __int64 LL;
#define NN 1000010
struct node
{
    int l,r;
    int id;
}q[NN];
bool cmp(node t1,node t2)
{
    return t1.r<t2.r;
}
int mx[NN*3];
LL sum[NN*3];
void push_up(int id)
{
    sum[id]=sum[id<<1]+sum[id<<1|1];
    mx[id]=max(mx[id<<1],mx[id<<1|1]);
}
int MAX;
LL SUM;
void build()
{
    memset(mx,0,sizeof(mx));
    memset(sum,0,sizeof(sum));
}
void update(int id,int L,int R,int pos,int val,int mxx)
{
    if(L==R)
    {
        sum[id]=(LL)val;
        mx[id]=mxx;
        return ;
    }
    int mid=(L+R)>>1;;
    if(pos<=mid)
        update(id<<1,L,mid,pos,val,mxx);
    else
        update(id<<1|1,mid+1,R,pos,val,mxx);
    push_up(id);
}
void query(int id,int L,int R,int l,int r)
{
    if(l<=L&&R<=r)
    {
        MAX=max(MAX,mx[id]);
        SUM+=sum[id];
        return ;
    }
    int mid=(L+R)>>1;
    if(l<=mid)
        query(id<<1,L,mid,l,r);
    if(mid<r)
        query(id<<1|1,mid+1,R,l,r);
}
int a[NN],p[NN],pre[NN];
inline int getint()
{
    int c;
    while (c = getchar(), c<'0' || '9'<c);
    int res = c - 48;
    while (c = getchar(), '0' <= c&&c <= '9') res = (res << 3) + res + res + c - 48;
    return res;
}
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++) a[i]=getint();
        for(int i=1;i<=m;i++)
        {
            q[i].l=getint();
            q[i].r=getint();
            q[i].id=i;
        }
        sort(q+1,q+m+1,cmp);
        build();
        memset(p,0,sizeof(p));
        memset(pre,0,sizeof(pre));
        for(int i=1;i<=n;i++)
        {
            pre[i]=p[a[i]];
            p[a[i]]=i;
        }
        int t=1;
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++)
        {
            update(1,1,n,i,a[i],pre[i]);
            while(i==q[t].r)
            {
                SUM=0;
                MAX=0;
                LL tt=(LL)(q[t].r-q[t].l+1);
                //printf("%d %d  %d??\n",q[t].l,q[t].r,q[t].id);
                LL sum=tt*(tt+1)/2;
                query(1,1,n,q[t].l,q[t].r);
                //printf("%I64d %d   %I64d  %d\n",tmp.sum,tmp.mx ,sum,q[t].l);
                if(sum==SUM && MAX < q[t].l)
                {
                    p[q[t].id]=1;
                }
                ++t;
            }
        }
        for(int i=1;i<=m;i++)
        {
            if(p[i]==1)
                puts("YES");
            else puts("NO");
        }

    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值