• LUOGU P4168 [Violet]蒲公英


    传送门

    解题思路

    分块码农题,设分成T块,cnt[i][j][k]表示第i块到第j块,k出现的次数,需要离散化。all[i][j] 表示第i块到第j块的众数。然后这两个数组先预处理出来。然后询问的时候先将答案设成区间大块的众数,然后剩余部分暴力往cnt里加来更新答案。T取n^(1/3)时最优,时间复杂度O(n^(5/3))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    
    using namespace std;
    const int MAXN = 40005;
    const int MAXSIZ = 40;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    
    int n,m,a[MAXN],cnt[MAXSIZ][MAXSIZ][MAXN],now,all[MAXSIZ][MAXSIZ];
    int sum[MAXSIZ][MAXSIZ];
    int bl[MAXN],l[MAXSIZ],r[MAXSIZ],siz,num,cpy[MAXN],rk[MAXN];
    
    inline int query(int x,int y){
    //  cout<<bl[x]<<" "<<bl[y]<<endl;
        int ret=0,mx=0;
        if(bl[x]==bl[y]){
            for(register int i=x;i<=y;i++){
                int k=rk[i];
                cnt[0][0][k]++;
                if(cnt[0][0][k]>mx) {mx=cnt[0][0][k];ret=a[i];}
                else if(cnt[0][0][k]==mx && a[i]<ret) ret=a[i];
            }
            for(register int i=x;i<=y;i++){
                int k=rk[i];
                cnt[0][0][k]--;
            }
            return ret;
        }ret=all[bl[x]+1][bl[y]-1];mx=sum[bl[x]+1][bl[y]-1];
    //  cout<<ret<<" "<<mx<<endl;
    //  cout<<r[bl[x]]<<" "<<l[bl[y]]<<endl;
        for(register int i=x;i<=r[bl[x]];i++){
            int k=rk[i];
            cnt[bl[x]+1][bl[y]-1][k]++;
            if(cnt[bl[x]+1][bl[y]-1][k]>mx) ret=a[i],mx=cnt[bl[x]+1][bl[y]-1][k];
            else if(cnt[bl[x]+1][bl[y]-1][k]==mx && a[i]<ret) ret=a[i];
        }
        for(register int i=l[bl[y]];i<=y;i++){
            int k=rk[i];
            cnt[bl[x]+1][bl[y]-1][k]++;
            if(cnt[bl[x]+1][bl[y]-1][k]>mx) ret=a[i],mx=cnt[bl[x]+1][bl[y]-1][k];
            else if(cnt[bl[x]+1][bl[y]-1][k]==mx && a[i]<ret) ret=a[i];
        }
        for(register int i=x;i<=r[bl[x]];i++){
            int k=rk[i];
            cnt[bl[x]+1][bl[y]-1][k]--;
        }
        for(register int i=l[bl[y]];i<=y;i++){
            int k=rk[i];
            cnt[bl[x]+1][bl[y]-1][k]--;
        }
        return ret;
    }
    
    int main(){
    //  freopen("data.txt","r",stdin);
    //  freopen("A.txt","w",stdout);
        n=rd(),m=rd();
        for(register int i=1;i<=MAXSIZ;i++) 
            if(i*i*i>=n) {num=i;break;}
        siz=n/num;num++;
        for(register int i=1;i<=n;i++) bl[i]=(i-1)/siz+1;
        for(register int i=1;i<=num;i++) l[i]=(i-1)*siz+1,r[i]=i*siz;r[num]=n;
        for(register int i=1;i<=n;i++) a[i]=rd(),cpy[i]=a[i];sort(cpy+1,cpy+1+n);
        now=unique(cpy+1,cpy+1+n)-cpy-1;
        for(register int i=1;i<=n;i++) rk[i]=lower_bound(cpy+1,cpy+1+now,a[i])-cpy;
        for(register int i=1;i<=num;i++)
            for(register int j=i;j<=num;j++)
                for(register int k=l[i];k<=r[j];k++){
                    int p=rk[k];
                    cnt[i][j][p]++;if(cnt[i][j][p]>sum[i][j] 
                    or (cnt[i][j][p]==sum[i][j] && a[k]<all[i][j]))
                    sum[i][j]=cnt[i][j][p],all[i][j]=a[k];
                }
        int pre=0,x,y;
        while(m--){
            x=rd(),y=rd();x=(x+pre-1)%n+1;y=(y+pre-1)%n+1;
            if(x>y) swap(x,y);pre=query(x,y);
    //      cout<<x<<" "<<y<<endl;
            printf("%d
    ",pre);
        }
        return 0;
    } 
    
    
  • 相关阅读:
    JSP中文乱码的一点研究
    Eclipse 导入外部项目无法识别为web项目并且无法在部署到tomcat下
    DOS命令学习
    Oracle学习笔记(一)
    登录时候的图片验证码的实现
    DIY随机数产生类
    使用VS2010建模
    Random快速连续产生不相同随机数
    魔兽争霸3冰封王座英雄以及兵种语言
    取两个地图坐标之间的距离
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9676838.html
Copyright © 2020-2023  润新知