作业1:新年组队

然而我第一次打的代码被狗吃了

新年组队(gdfzoj 64)

Problem Description

BNU ACM校队有n名队员,从1到n标号,每名队员根据自身情况拥有一个特征值,其中第i名队员的特征值是a[i],
现在BOSS问了m个问题,每个问题给定[l,r],要求小Q同学马上从标号位于区间[l,r]内的队员中选出两名队员,使得这两名队员的特征值相同,
并且不默契度要尽可能小,两名队员的不默契度定义为两名队员标号之差的绝对值。对此小Q同学倍感压力,急需你的帮助。

Input

第一行包含2个整数n、m。

第二行包含n个整数a[1]、a[2]、…、a[n],保证0<=a[i]<2^31。

接下来m行,每行包含2个整数l、r,请注意所给的l、r均是经过加密的,解密方式是l=l xor lastans、r=r xor lastans,其中lastans表示上一次操作的输出结果,初始lastans=0,保证解密后1<=l<=r<=n。

对于30%的数据,1<=n,m<=5000。

对于60%的数据,1<=n,m<=50000。

对于100%的数据,1<=n,m<=500000。

Output

输出m行,每行包含一个整数,表示最小的两名队员的不默契度,如果不能选出满足条件的两名队员,请输出-1。

Sample Input

5 3

1 1 2 5 2

1 5

3 5

-4 -6

Sample Output

1

-1

2

思路

这道题就是一个分块吧,反正应该是吧,我并没有听到这道题的讲解,所以自己做起来还是很难的,因为有师兄的标程,所以多少有点像
由题可以看出是强制在线,f[左边的块][右边的块]
初始化时拿f[i][j-1],f[j][j]刷新发f[i][j]
查询时看[l,r]能否完全覆盖几个块,可以则刷新答案,不行则for枚举。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[5000005],q[5000005],b[5000005],c[5000005]={2147483647},s[5000005];
int f[5001][5001]={2147483647};
int i,j,k,n,m,ls,ki,x,y,ans;
int jm(int o,int p) {
    return o^p;
}
int cmp(int ii,int jj) {
    return a[ii]==a[jj]?ii<jj:a[ii]<a[jj];
}
int main(){
    ```//------------初始化-------------```
    scanf("%d%d",&n,&m);
    ki=(n/5000)+1;
    for (i=1;i<=n;i++) scanf("%d",&a[i]);    //读入
    for (i=1;i<=n;i++) q[i]=i;
    sort(q+1,q+1+n,cmp); //离散化
    for (i=1;i<=n;i++) if (a[q[i]] == a[q[i-1]]) b[q[i-1]]=q[i]; 
    //寻找下一个特征值相同的人
    for (i=1;i<=n;i++) if (b[i]) c[i]=b[i]-i; //不默契度
    for (i=1;i<=n;i++) s[i]=(i-1)/5000; //查找每一人位于第几个块

    //处理f
    for (i=1;i<=ki;i++) if (b[i] != 0) {
        f[s[i]][s[q[i]]]=min(f[s[i]][s[q[i]]],c[i]); 
    }
    for (int i=1;i<=ki;i++) for (int j=i+1;j<=ki;j++) {
        f[i][j]=min(f[j][j],min(f[i][j],f[i][j-1]));
    //
    ```//-----------------------查找--------------```
    for (int op=0;op<m;op++) {
        scanf("%d%d",&x,&y);
        x=jm(x,ans); y=jm(y,ans); 
        ans=2147483647;
        if (s[y]-s[x] <=1) {
            for (int i=x;i<=y;i++) {
                if (b[i]>0 && b[i]<=y) ans=min(ans,c[i]); 
            }
            if (ans>5000000) ans=-1;
            printf("%d\n",ans);
        } else {
            ans=f[s[x]+1][s[y]-1];
            for (j=x;j<=s[x]*5000;j++) {
                if (b[j]>0 && b[j]<=y) ans=min(ans,c[j]); 
            }
            for (j=s[y]*5000-5000;j<=y;j++) {
                if (b[j]>0 && b[j]<=y) ans=min(ans,c[j]); 
            }
            if (ans>5000000) ans=-1;
            printf("%d\n",ans);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值