zoukankan      html  css  js  c++  java
  • P5048 题解

    吐槽:感觉本题最多紫。


    考虑分块,设块长为 (S)

    离散化序列之后,设 (f_{i,j}) 表示第 (i,i+1,dots,j) 块的众数出现次数,可以在 (O((dfrac{n}{S})^2 imes S))=O(dfrac{n^2}{S})) 时间内预处理出来。

    查询的时候先把整段的答案算出来,考虑零碎部分怎么算。

    设目前算出的众数的出现数量为 (ans)

    此时传统的做法是值域分块查询这个数在一个区间中出现次数,但是我们要算的比这个弱很多,只要判断这个数在这个区间内出现次数为 (ans+1) 即可。

    那我们只要对每个值开个 vector,按顺序维护这个值对应的所有下标,然后判断左边零碎时我们只要判断在右边 (ans) 个是否在 ([l,r]) 中,判断右边零碎时我们只要判断在左边 (ans) 个是否在 ([l,r]) 中即可。

    时间复杂度 (O(dfrac{n^2}{S}+mS)),空间复杂度 (O(n))

    (S=dfrac{n}{sqrt m}) 可得复杂度为 (O(nsqrt m))

    一点也不卡常,习惯性开个论文鸽快读就过了。

    Code
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct IO_Tp {
        const static int _I_Buffer_Size = 2 << 23;
        char _I_Buffer[_I_Buffer_Size], *_I_pos = _I_Buffer;
    
        const static int _O_Buffer_Size = 2 << 23;
        char _O_Buffer[_O_Buffer_Size], *_O_pos = _O_Buffer;
    
        IO_Tp() { fread(_I_Buffer, 1, _I_Buffer_Size, stdin); }
        ~IO_Tp() { fwrite(_O_Buffer, 1, _O_pos - _O_Buffer, stdout); }
    
        IO_Tp &operator>>(int &res) {
        	int f=1;
            while (!isdigit(*_I_pos)&&(*_I_pos)!='-') ++_I_pos;
            if(*_I_pos=='-')f=-1,++_I_pos;
            res = *_I_pos++ - '0';
            while (isdigit(*_I_pos)) res = res * 10 + (*_I_pos++ - '0');
            res*=f;
            return *this;
        }
    
        IO_Tp &operator<<(int n) {
        	if(n<0)*_O_pos++='-',n=-n;
            static char _buf[10];
            char *_pos = _buf;
            do
                *_pos++ = '0' + n % 10;
            while (n /= 10);
            while (_pos != _buf) *_O_pos++ = *--_pos;
            return *this;
        }
    
        IO_Tp &operator<<(char ch) {
            *_O_pos++ = ch;
            return *this;
        }
    } IO;
    const int N=500005,S=715;
    int n,m,bl,num,a[N],b[N],L[S],R[S],f[S][S],tot[N],pl[N];
    vector<int>v[N];
    int query(int l,int r){
    	int ret=0;
    	if(b[l]==b[r]){
    		for(int i=l;i<=r;i++)ret=max(ret,++tot[a[i]]);
    		for(int i=l;i<=r;i++)tot[a[i]]=0;
    		return ret;
    	}
    	ret=f[b[l]+1][b[r]-1];
    	for(int i=l;i<=R[b[l]];i++)while(pl[i]+ret<v[a[i]].size()&&v[a[i]][pl[i]+ret]<=r)ret++;
    	for(int i=L[b[r]];i<=r;i++)while(pl[i]-ret>=0&&v[a[i]][pl[i]-ret]>=l)ret++;
    	return ret;
    } 
    int main(){
    	IO>>n>>m;
    	for(int i=1;i<=n;i++)IO>>a[i],b[i]=a[i];
    	sort(b+1,b+n+1);
    	num=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+num+1,a[i])-b,pl[i]=v[a[i]].size(),v[a[i]].push_back(i);
    	bl=sqrt(n);
    	for(int i=1;i<=n;i++)b[i]=(i-1)/bl+1;
    	num=b[n];
    	for(int i=1;i<=num;i++)L[i]=R[i-1]+1,R[i]=i*bl;
    	R[num]=n;
    	for(int i=1;i<=num;i++){
    		memset(tot,0,sizeof(tot));
    		for(int j=i;j<=num;j++){
    			f[i][j]=f[i][j-1];
    			for(int k=L[j];k<=R[j];k++)f[i][j]=max(f[i][j],++tot[a[k]]);
    		}
    	}
    	memset(tot,0,sizeof(tot));
    	for(int lastans=0;m--;){
    		int l,r;
    		IO>>l>>r;
    		l^=lastans,r^=lastans;
    		IO<<(lastans=query(l,r))<<'
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    SQL 语言入门
    [转载]Sql Server 中的Login,Schema,User,Role之间的关系
    稀疏矩阵运算
    特征缩放的几种方法
    dp解出栈序列数
    神经网络解决多分类问题例:数字识别
    多分类例题
    fminunc 函数的用法
    二分类
    特征归一化、特征映射、正则化
  • 原文地址:https://www.cnblogs.com/happydef/p/13927132.html
Copyright © 2011-2022 走看看