GTY's gay friends

题目链接

英文版

GTY's gay friends

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


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
 
英语版

GTY's gay friends


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


问题描述
 GTY有n个基友,出于某种恶趣味,GTY每天早上会让他的基友们排成一行,每个基友有一个特征值,表示基友有多雄壮或娘炮,你,作为GTY的助手,必须回答GTY的每个询问,GTY每次会问一个区间
    
    
     
     [l,r]
    
    是否为一个
    
    
     
     1
    
    
    
    
     
     rl+1
    
    的排列。
输入描述
多组数据(约3组),每组数据的第一行有两个数
    
    
     
     n,m(1n,m100000)
    
     表示初始基友数量和询问个数,第二行包含
    
    
     
     n
    
    个数
    
    
     
     ai(1ain)
    
    表示基友的特征值,接下来
    
    
     
     m
    
    行每行两个数
    
    
     
     l,r
    
    表示询问
    
    
     
     [l,r]
    
    是否为一个排列。
输出描述
对于每个询问,若它是一个排列,输出”YES”,否则输出”NO”
输入样例
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
输出样例
YES
NO
YES
YES
YES
YES
NO

/*
一个区间是排列只需要区间和为len(len+1)2(len为区间长度),
且互不相同,对于第一个问题我们用前缀和解决,
对于第二个问题,
预处理每个数的上次出现位置,记它为pre,
互不相同即区间中pre的最大值小于左端点,
使用线段树或Sparse Table.
即可在O(n)/O(nlogn)的预处理后 O(logn)/O(1)回答每个询问.
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000000+10;
int n,m,x,y;
int sum[maxn<<2],t,pre[maxn],anx[maxn];
__int64 S[maxn];
void pushup(int rt) {
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}
void build(int l,int r,int rt) {
    if(l==r) {
        sum[rt]=pre[l];
        // printf("[%d]\n",l);
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt) {
    if(L<=l&&r<=R) {
        return sum[rt];
    }
    int mid=(l+r)>>1;
    int ret=0;
    if(L<=mid) {
        ret=max(ret,query(L,R,l,mid,rt<<1));
    }
    if(R>mid) {
        ret=max(ret,query(L,R,mid+1,r,rt<<1|1));
    }
    return ret;
}


int main() {
    //freopen("D://imput.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)) {
        S[0]=0;
        memset(anx,0,sizeof(anx));
        for(int i=1; i<=n; i++) {
            scanf("%d",&t);
            pre[i]=anx[t];
            anx[t]=i;
            S[i]=S[i-1]+t;
        }
        build(1,n,1);
        while(m--) {
            scanf("%d%d",&x,&y);
            int len = y-x+1;
            __int64 res=(__int64)len*(len+1);
            if(S[y]-S[x-1]!=res/2LL) {
                printf("NO\n");
            } else {
                int t=query(x,y,1,n,1);
                printf("%s\n",t<x?"YES":"NO");//互不相同即区间中pre的最大值小于左端点,
            }
        }
    }
    return 0;
}


方法二:

/*
一个集合的hash值为元素的异或和,
预处理[1..n]的排列的hash和原序列的前缀hash异或和,
就可以做到线性预处理,O(1)回答询问.
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <algorithm>
using namespace std;
const int maxn=1000000+5;
typedef __int64 LL;
int n,m,t,l,r;
LL Hash[maxn],xr[maxn],xt[maxn],Xor[maxn],Sxt[maxn];
int main() {
    srand(time(0));
    for(int i=1; i<maxn; i++) {
        Hash[i]=(LL)rand()*rand();
        xr[i]=xr[i-1]^Hash[i];
        xt[i]=xt[i-1]+i;
    }
    while(~scanf("%d%d",&n,&m)) {
        memset(Sxt,0,sizeof(Sxt));
        memset(Xor,0,sizeof(Xor));
        for(int i=1; i<=n; i++) {
            scanf("%d",&t);
            Sxt[i]=Sxt[i-1]+t;
            Xor[i]=Xor[i-1]^Hash[t];
        }
        while(m--) {
            scanf("%d%d",&l,&r);
            if(Sxt[r]-Sxt[l-1]==xt[r-l+1]&&(Xor[r]^Xor[l-1])==xr[r-l+1]) {
                printf("YES\n");
            } else {
                printf("NO\n");
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值