zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    【转载】jquery取得iframe元素的方法
    【转载】URL重写相关
    【转载】PHP程序员突破成长瓶颈
    【转载】是什么浪费了我的上网时间
    信息化时代下的我们弄潮儿
    如何减小与“大牛”的差距
    servlet应用之cookies&session操作
    Servlet简介及工作原理
    深入学习Tomcat自己动手写服务器(附服务器源码)
    servlet过滤器
  • 原文地址:https://www.cnblogs.com/bennettz/p/8526379.html
Copyright © 2011-2022 走看看