• CodeChef:Chef and Problems(分块)


    CodeChef:Chef and Problems

    题目大意

    有一个长度为n的序列$a_1,a_2,……,a_n$,每次给出一个区间[l,r],求在区间内两个相等的数的最远距离($max(j-i,满足a_i==a_j且lle i,j le r)$)

    思路:

    分块将序列分成sqrt(n)块
    预处理出每个数在每个块之后出现的最早位置和在每个块之前出现的最晚位置O(msqrt(n))
    然后就可以按块进行区间DP,求出所有块之间的最大值 O(nsqrt(n))

    答案就是max(f[L][R](两个数都在[L,R]里面的答案)O(1)
    两个数都在[L,R]外面的答案,O(sqrt(n))
    一个数在[L,R]里面,一个在外面的答案 O(sqrt(n)) )

    总复杂度O(nsqrt(n))

    具体实现看代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define maxn 100005
    #define maxs 350
    #define inf 0x3fffff
    int block[maxn],a[maxn],size,f[maxs][maxs],pre[maxn][maxs],nex[maxn][maxs],mi[maxn];
    int main(){
    //    freopen("1.in","r",stdin);
        int n,m,q,l,r;scanf("%d%d%d",&n,&m,&q);size=sqrt(n);
        for(int i=1;i<=n;i++)scanf("%d",a+i),block[i]=(i-1)/size+1;
        //预处理出每个数在每个块之后出现的最早位置和在每个块之前出现的最晚位置O(msqrt(n))  
        for(int i=1;i<=n;i++)nex[a[i]][block[i]]=i;
        for(int i=n;i>=1;i--)pre[a[i]][block[i]]=i;
        for(int i=1;i<=m;i++){
            pre[i][block[n]+1]=inf;
            for(int j=block[n];j>=1;j--){
                if(!pre[i][j])pre[i][j]=inf;
                pre[i][j]=min(pre[i][j],pre[i][j+1]);
            }
            for(int j=1;j<=block[n];j++){
                nex[i][j]=max(nex[i][j],nex[i][j-1]);
            }
        }
        //按块进行区间DP,求出所有块之间的最大值
        for(int i=block[n];i>=1;i--){
            for(int j=i;j<=block[n];j++){
                f[i][j]=max(f[i][j-1],f[i+1][j]);
                for(int k=(i-1)*size+1,l=i*size;k<=l;k++){
                    f[i][j]=max(f[i][j],nex[a[k]][j]-k);
                }
            }
        }
        for(int i=0;i<q;i++){
            scanf("%d%d",&l,&r);
            int L=block[l]+1,R=block[r]-1,ans=f[L][R];
            //求出左端点在[L,R]外,右端点在[L,R]里面的答案 
            for(int j=l;block[j]==block[l];j++)if(!mi[a[j]])mi[a[j]]=j,ans=max(ans,nex[a[j]][R]-j);
            for(int j=r;block[j]==block[r];j--){
                ans=max(ans,j-(mi[a[j]]?mi[a[j]]:j));//求出两个端点都在[L,R]外的答案 
                ans=max(ans,j-pre[a[j]][L]);//求出右端点在[L,R]外,左端点在[L,R]里面的答案 
            }
            for(int j=l;block[j]==block[l];j++)mi[a[j]]=0;
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    python数据库小脚本
    替换debug
    监听属性变化
    ast binding
    还原未修改的常量
    数据库中常用查询
    职业生涯四个阶段
    如何控制需求
    如何将VS Code 切换成中文
    当同时使用bootstrapdatepicker.js和jquery.validate.js这两款插件,至少要选择两次时间,才能验证成功的问题
  • 原文地址:https://www.cnblogs.com/bennettz/p/8526379.html
Copyright © 2020-2023  润新知