• OneInDark对众数的爱


    前言

    找不到在哪里提交只能口胡了。

    题目

    找到了!

    蒲公英(洛谷)

    还有一道类似的

    [Ynoi2019 模拟赛] Yuno loves sqrt technology III(洛谷)

    题目描述

    ( exttt{OneInDark}) 有一个长度为 (n) 的序列 (a)

    这一天他找到了你,由于他很喜欢热闹,所以他想询问区间内的众数是什么。

    他很专一,所以如果有多个答案,只需要输出编号最小的即可。

    而且他喜欢一问一答的交互方式,所以这道题是强制在线。

    因为他很强,所以他早就算出了答案,只是需要你与他对一下答案而已。

    他有时候也喜欢整蛊,所以他需要你在 (2s) 内算出答案,不然会遭到惩罚。

    数据范围

    ( exttt{OneInDark}) 还是很善解人意的,所以他不会让你很累。

    (nle 4*10^4,mle 5*10^4,a_ile 10^9)

    讲解

    首先我们可以离散化。

    考虑分块。

    我们可以先用 (O(nsqrt{n})) 的时间复杂度预处理出任意两个块之间形成的区间的众数,以及其出现次数。

    我们令 (f[l][r]) 表示 块(l) 到 块(r) 的众数。

    对于每个询问,我们考虑答案只可能是这两种情况:

    • 在大块中。

    • 在零散小块中。

    对于第一种情况,答案就是 (f[l][r])

    对于第二种情况,我们考虑零散的数只有 (sqrt{n}) 级别个。

    对于每个数,我们记录一下它们出现的位置(预处理)。

    然后我们对于零散的数可以二分出其在区间内的出现次数。

    时间复杂度为 (O(msqrt{n}logn))好像已经可以过了

    考虑优化。

    我们令 (pos[i][j]) 表示 (i) 在数列中第 (j) 次出现的位置。

    (t[i]) 表示 (a[i]) 在数列中是第几次出现。

    显然我们枚举的零散的数的时候,我们可以将其当做第一次出现。

    此时我们需要一个计数的变量 (MAX),其初值为 (f[l][r])

    如果当前枚举的这个数 (a[i]),满足 (pos[a[i]][MAX] le qr) (qr为询问区间的右端点)。

    那么我们可以继续向右扩展,显然 (MAX) 总共最多只会扩展 (sqrt{n}) 级别次。

    (n,m) 基本同阶,所以总时间复杂度为 (O(nsqrt{n}))

    代码

    蒲公英

    //12252024832524
    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 40005;
    const int MAXB = 205;
    int n,m,lshtot,ans,B;
    int to[MAXN];
    struct node
    {
    	int val,lsh,ID;
    }s[MAXN];
    bool cmp1(node x,node y){return x.val < y.val;}
    bool cmp2(node x,node y){return x.ID < y.ID;}
    
    LL Read()
    {
    	LL x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x);
    	if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int f[MAXB][MAXB],cs[MAXB][MAXB],bl[MAXN];
    int cnt[MAXN],t[MAXN];
    vector<int> pos[MAXN];
    
    void pre()
    {
    	for(int i = 1;i <= lshtot;++ i) pos[i].push_back(0);
    	for(int i = 1;i <= n;++ i) pos[s[i].lsh].push_back(i),t[i] = pos[s[i].lsh].size()-1;
    	for(int i = 1;i <= n;i += B)
    	{
    		int zs = n+1;//众数 
    		for(int j = i;j <= n;++ j)
    		{
    			int val = s[j].lsh;
    			cnt[val]++;
    			if(cnt[val] > cnt[zs] || (cnt[val] == cnt[zs] && val < zs)) zs = val;
    			if(bl[j] != bl[j+1]) f[bl[i]][bl[j]] = zs,cs[bl[i]][bl[j]] = cnt[zs];
    		}
    		for(int j = i;j <= n;++ j) cnt[s[j].lsh] = 0;
    		if(i == 1) i--;
    	}
    }
    int spsolve(int l,int r)
    {
    	int ret = 0;
    	for(int i = l;i <= r;++ i)
    	{
    		int val = s[i].lsh;
    		cnt[val]++;
    		if(cnt[val] > cnt[ret] || (cnt[val] == cnt[ret] && val < ret)) ret = val;
    	}
    	for(int i = l;i <= r;++ i) cnt[s[i].lsh] = 0;
    	return ret;
    }
    int solve(int l,int r)
    {
    	int L = bl[l],R = bl[r],ret = 0;
    	if(L == R) return spsolve(l,r);
    	if(bl[l] == bl[l-1]) L++;
    	if(bl[r] == bl[r+1]) R--;
    	if(L <= R) ret = f[L][R];
    	int MAX = cs[L][R];
    	for(int i = l;bl[i] != L;++ i)
    	{
    		int now = t[i],val = s[i].lsh;
    		while(pos[val].size()-1 >= now + MAX && pos[val][now+MAX] <= r) MAX++,ret = val;
    		if(pos[val].size()-1 >= now + MAX - 1 && pos[val][now+MAX-1] <= r && val < ret) ret = val;
    	}
    	for(int i = (R+1)*B;i <= r;++ i)
    	{
    		int now = t[i],val = s[i].lsh;
    		while(now - MAX > 0 && pos[val][now-MAX] >= l) MAX++,ret = val;
    		if(now - MAX + 1 > 0 && pos[val][now-MAX+1] >= l && val < ret) ret = val;
    	}
    	return ret;
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); m = Read();
    	for(int i = 1;i <= n;++ i) s[i].val = Read(),s[i].ID = i;
    	sort(s+1,s+n+1,cmp1);
    	for(int i = 1;i <= n;++ i)
    		if(s[i].val == s[i-1].val) s[i].lsh = s[i-1].lsh;
    		else s[i].lsh = ++lshtot,to[lshtot] = s[i].val;
    	sort(s+1,s+n+1,cmp2);
    	B = sqrt(n);
    	for(int i = 1;i <= n;++ i) bl[i] = i / B;
    	pre();
    	for(int i = 1;i <= m;++ i)
    	{
    		int l = (Read() + ans - 1) % n + 1,r = (Read() + ans - 1) % n + 1;
    		if(l > r) swap(l,r);
    		Put(ans = to[solve(l,r)],'
    ');
    	}
    	return 0;
    }
    

    Yuno loves sqrt technology III

    这种离散化更快哦

    //12252024832524
    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 500005;
    const int MAXB = 710;
    int n,m,len,ans,B;
    int a[MAXN],b[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x);
    	if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int f[MAXB][MAXB],cs[MAXB][MAXB],bl[MAXN];
    int cnt[MAXN],t[MAXN];
    vector<int> pos[MAXN];
    
    void pre()
    {
    	for(int i = 1;i <= len;++ i) pos[i].push_back(0);
    	for(int i = 1;i <= n;++ i) pos[a[i]].push_back(i),t[i] = pos[a[i]].size()-1;
    	for(int i = 1;i <= n;i += B)
    	{
    		int zs = n+1;//众数 
    		for(int j = i;j <= n;++ j)
    		{
    			int val = a[j];
    			cnt[val]++;
    			if(cnt[val] > cnt[zs] || (cnt[val] == cnt[zs] && val < zs)) zs = val;
    			if(bl[j] != bl[j+1]) f[bl[i]][bl[j]] = zs,cs[bl[i]][bl[j]] = cnt[zs];
    		}
    		for(int j = i;j <= n;++ j) cnt[a[j]] = 0;
    		if(i == 1) i--;
    	}
    }
    int spsolve(int l,int r)
    {
    	int ret = 0;
    	for(int i = l;i <= r;++ i)
    	{
    		int val = a[i];
    		cnt[val]++;
    		if(cnt[val] > cnt[ret] || (cnt[val] == cnt[ret] && val < ret)) ret = val;
    	}
    	ret = cnt[ret];
    	for(int i = l;i <= r;++ i) cnt[a[i]] = 0;
    	return ret;
    }
    int solve(int l,int r)
    {
    	int L = bl[l],R = bl[r];
    	if(L == R) return spsolve(l,r);
    	if(bl[l] == bl[l-1]) L++;
    	if(bl[r] == bl[r+1]) R--;
    	int MAX = cs[L][R];
    	for(int i = l;bl[i] != L;++ i)
    	{
    		int now = t[i],val = a[i];
    		while(pos[val].size()-1 >= now + MAX && pos[val][now+MAX] <= r) MAX++;
    	}
    	for(int i = (R+1)*B;i <= r;++ i)
    	{
    		int now = t[i],val = a[i];
    		while(now - MAX > 0 && pos[val][now-MAX] >= l) MAX++;
    	}
    	return MAX;
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); m = Read();
    	for(int i = 1;i <= n;++ i) a[i] = b[i] = Read()+1;
    	sort(b+1,b+n+1);
    	len = unique(b+1,b+n+1)-b;
    	for(int i = 1;i <= n;++ i) a[i] = lower_bound(b+1,b+len+1,a[i])-b;
    	B = sqrt(n);
    	for(int i = 1;i <= n;++ i) bl[i] = i / B;
    	pre();
    	for(int i = 1;i <= m;++ i)
    	{
    		int l = Read() ^ ans,r = Read() ^ ans;
    		if(l > r) swap(l,r);
    		Put(ans = solve(l,r),'
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux防火墙管理(iptables)以及开放端口配置
    CSS 样式引入方式、常用选择器以及优先级权重的计算
    初识外边距合并-margin collapsing
    纯CSS实现自适应正方形
    常用正则
    vue 学习记录
    VScode 之快速创建vue模板
    vscode之常用插件
    工具函数
    Axios之配置参数
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14406875.html
Copyright © 2020-2023  润新知