【AcWing 249. 蒲公英】

【AcWing 249. 蒲公英】

题意:

长度为n的序列,给定区间,求区间众数,如果出现次数相同,输出编号最小的

题解:

区间众数,不带修改,强制在线(否则可以莫队)
没有什么好办法那就只能暴力分块
分块,预处理任意两个大块之间的众数,相当于求出所有后缀的众数情况(枚举左块的端点,n*sqrt(n))
询问[l,r]中众数肯定是大块idl+1 ~ idr-1的众数,或者小块中的某个数
这一共是有sqrt(n)个候选答案,需要统计其在区间[l,r]内的出现次数,
第一个方法是用adj[x]记录x的所有出现次数,那么x在[l,r]内的出现次数就是:

upper_bound(adj[x].begin(), adj[x].end(), r) - lower_bound(adj[x].begin(), adj[x].end(), l)

这个做法的复杂度是O(nsqrt(n)logn)
第二个方法是预处理每个数在所有块中出现次数的前缀(n*sqrt(n)),这样直接就可以用差分来求次数,可以省掉第一个方法中的查找(去掉log),复杂度O(nsqrt(n))

代码:

代码有详细注释
貌似方法一会超时,只有方法二可以过

方法一:

#pragma optimize("Ofast")
#include<bits/stdc++.h>
#define MAXN 40005
#define MAXB 2005
using namespace std;
typedef long long ll;int N,M,B;
int a[MAXN], c[MAXN];
int d[MAXB][MAXB];vector<int> adj[MAXN];void init(){int cnt[MAXN], res;for(int l=0;l<=N;l+=B)//枚举左块 {if(l==0) continue;memset(cnt, 0, sizeof(cnt));res = 0;for(int r=l;r<=N;r++)//枚举右边界 {++cnt[a[r]];bool f1=cnt[a[r]] > cnt[res];//出现次数最多 bool f2=( cnt[a[r]] == cnt[res] && a[r] < res);//出现次数一样,编号更小 if(f1||f2) res = a[r];if((r+1)%B==0 || r==N) d[l/B][r/B] = res;//第l/B块到第r/B块的众数是res }}
}inline int num(const int& l, const int& r, const int& x){//在[l,r]范围内x出现几次 return upper_bound(adj[x].begin(), adj[x].end(), r) - lower_bound(adj[x].begin(), adj[x].end(), l);
}int query(int l, int r){int ans = 0;int idl = l/B, idr = r/B;if(idl-1 < idr) //如果idl在idr的左侧(或者一样) ans = d[idl+1][idr-1];int n = num(l,r,ans), n1;//n和n1表示出现数量//ans为出现次数最多的数的编号 //-----以下为分块的常规操作 if(idl==idr){for(int i=l;i<=r;i++){n1 = num(l,r,a[i]);//查看块内是否有数字大于n if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1;}}else{for(int i=l;i<(idl+1)*B;i++){n1 = num(l,r,a[i]);if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1;}for(int i=idr*B;i<=r;i++){n1 = num(l,r,a[i]);if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1;}}return c[ans];
}int main(){scanf("%d%d", &N, &M);B = sqrt(N); for(int i=1;i<=N;i++){scanf("%d", &a[i]);}memcpy(c,a,sizeof(a));sort(c+1, c+1+N);for(int i=1;i<=N;i++){a[i] = lower_bound(c+1, c+1+N, a[i]) - c;adj[a[i]].push_back(i);//a[i]在哪些位置出现过 }//init();int last = 0, l, r;while(M--){scanf("%d%d", &l, &r);l = (l+last-1)%N + 1;r = (r+last-1)%N + 1;if(l > r) swap(l, r);//cout<<"l r "<<l<<" "<<r<<endl;last = query(l,r);printf("%d\n", last);}return 0;
}

方法二:

#pragma optimize("Ofast")
#include<bits/stdc++.h>
#define MAXN 40005
#define MAXB 2005
using namespace std;
typedef long long ll;int N,M,B;
int a[MAXN], c[MAXN];
int s[MAXB][MAXN], d[MAXB][MAXB];inline int num(int idl, int idr, int x){//利用差分求出现次数 if(idl>idr) return 0;if(idl==0) return s[idr][x];else return s[idr][x] - s[idl-1][x];
}
int cnt[MAXN];
void init(){for(int i=0;i<N;i++){if(i>0 && i%B==0){//到了下一块 for(int j=0;j<N;j++){s[i/B][j] = s[i/B-1][j];//赋值前一块的情况 }}++s[i/B][a[i]];}// 上述内容为预处理每个数在所有块中出现次数的前缀 //下方内容为求出任意2个大块之间的众数int res;for(int l=0;l<N;l+=B){memset(cnt, 0, sizeof(cnt));res = 0;for(int r=l;r<N;r++){++cnt[a[r]];if(cnt[a[r]] > cnt[res] || cnt[a[r]] == cnt[res] && a[r] < res) res = a[r];if((r+1)%B==0 || (r+1)==N) d[l/B][r/B] = res;}}
}int query(int l, int r){int ans = 0;int idl = l/B + 1, idr = r/B - 1;if(idl <= idr) ans = d[idl][idr];int n = num(idl,idr,ans), n1;if(l/B == r/B){for(int i=l;i<=r;i++) ++cnt[a[i]];for(int i=l;i<=r;i++){if(cnt[a[i]]==0) continue;n1 = num(idl, idr, a[i]) + cnt[a[i]];if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1;cnt[a[i]] = 0;}}else{for(int i=l;i<idl*B;i++) ++cnt[a[i]];for(int i=(idr+1)*B;i<=r;i++) ++cnt[a[i]];for(int i=l;i<idl*B;i++){if(cnt[a[i]]==0) continue;n1 = num(idl, idr, a[i]) + cnt[a[i]];if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1;cnt[a[i]] = 0;}for(int i=(idr+1)*B;i<=r;i++){if(cnt[a[i]]==0) continue;n1 = num(idl, idr, a[i]) + cnt[a[i]];if(n < n1 || n == n1 && a[i] < ans) ans = a[i], n = n1;cnt[a[i]] = 0;}}return c[ans];
}int main(){//ios::sync_with_stdio(0);scanf("%d%d", &N, &M);B = sqrt(N); for(int i=0;i<N;i++){scanf("%d", &a[i]);}memcpy(c,a,sizeof(a));sort(c, c+N);for(int i=0;i<N;i++){a[i] = lower_bound(c, c+N, a[i]) - c;}//init();memset(cnt, 0, sizeof(cnt));int last = 0, l, r;while(M--){scanf("%d%d", &l, &r);l = (l+last-1)%N + 1;r = (r+last-1)%N + 1;if(l > r) swap(l, r);--l; --r;//cout<<"l r "<<l<<" "<<r<<endl;last = query(l,r);printf("%d\n", last);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318179.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

年末展望:Oracle 对 JDK收费和.NET Core 给我们的机遇

2018年就结束了&#xff0c;马上就要迎来2019年&#xff0c;这一年很不平凡&#xff0c;中美贸易战还在继续&#xff0c;IT互联网发生急剧变化&#xff0c;大量互联网公司开始裁员&#xff0c;微软的市值在不断上升 &#xff0c;在互联网公司的市值下跌过程中爬到了第一的位置&…

等比数列三角形 (数论 + 黄金分割点)+ JOISC 2016 Day3 T3 「电报」(基环树 + 拓扑排序)

文章目录T1&#xff1a;等比数列三角形题目题解代码实现T2&#xff1a;电报题目题解代码实现T1&#xff1a;等比数列三角形 题目 求三边都是 ≤n 的整数&#xff0c;且成等比数列的三角形个数 注意三角形面积不能为 0 注意 oeis 中未收录此数列&#xff0c;所以并不需要去搜了…

模板:笛卡尔树

介绍 笛卡尔树是一种非常特殊的二叉搜索树。每个节点有两个信息x和y。如果只考虑 x&#xff0c;它是一棵二叉搜索树&#xff0c;如果只考虑 y&#xff0c;它是一个小根堆。 实现 按照y升序插入 显然应该插入到一条极右链上 但为了维护x二叉搜索树的性质 对于右链上x>当前…

乱搞

占个坑&#xff0c;找时间补

【AcWing 243. 一个简单的整数问题2】

例题&#xff1a;【AcWing 243. 一个简单的整数问题2】 线段树模板题&#xff0c;区间修改区间求和。 题解&#xff1a; 将序列分成N/B块&#xff0c;维护&#xff1a; id[i] i/B&#xff0c;i所在块标号 res[id] 第id块的sum base[id] 第id块的add标记修改时&#xff0…

CF1540B-Tree Array【数学期望,dp】

正题 题目链接:https://www.luogu.com.cn/problem/CF1540B 题目大意 nnn个点的一棵树&#xff0c;开始随机选择一个点标记&#xff0c;然后每次随机选择一个与被标记点连边的点标记&#xff0c;按照标记顺序排列&#xff0c;求期望逆序对数。 1≤n≤2001\leq n\leq 2001≤n≤2…

使用PerfView监测.NET程序性能(三):分组

在上一篇博客使用PerfView监测.NET程序性能&#xff08;二&#xff09;&#xff1a;Perfview的使用中&#xff0c;我们通过Perfview帮助文件中自带的代码来简单使用了Perfview&#xff0c;了解了基本操作。现在来看看Perfview中的分组操作&#xff08;Grouping&#xff09;。分…

【做题记录】构造题

CF468C Hack it! 题意&#xff1a; 令 \(F(x)\) 表示 \(x\) 的各个位上的数字之和&#xff0c;如 \(F(1234)123410\) 。 给定 \(a(a\le 10^{18})\) &#xff0c;请求出任意一组 \(l,r(l,r\le 10^{200})\) &#xff0c;要求满足&#xff1a; \[\sum_{il}^{r}F(i)\pmod{a}0 \]输出…

主席树 学习报告

文章目录前言可持久化线段树代码区间第k大代码练习粟粟的书架代码森林代码任务查询系统代码列队代码前言 主席树&#xff0c;全称是可持久化权值线段树 利用r和l-1两棵权值线段树作差得到[l,r]的信息 从而解决各种问题 在排名这方面功能极其强大 可持久化线段树 学主席树之前…

Star Way To Heaven (prim最小生成树) // [ NOIP提高组 2014]飞扬的小鸟(DP)

文章目录T1&#xff1a;Star Way To Heaven题目题解代码实现T2&#xff1a;飞扬的小鸟题目题解代码实现T1&#xff1a;Star Way To Heaven 题目 小 w 伤心的走上了 Star way to heaven。 到天堂的道路是一个笛卡尔坐标系上一个 n*m 的长方形通道 顶点在 (0,0) 和 (n,m) 。 小…

CF1043E Train Hard, Win Easy

CF1043E Train Hard, Win Easy 题意&#xff1a; n个人有Ai和Bi两个属性&#xff0c;给出m个关系&#xff1a;xi yi表示xi和yi不能配对 i,j两人规定匹配的价值为min (Ai Bj , Bi Aj ) 回答出每个人跟所有人配对&#xff08;除开不能和自己匹配的人&#xff09;的价值总和 …

P7887-「MCOI-06」Existence of Truth【构造】

正题 题目连接:https://www.luogu.com.cn/problem/P7887?contestId52021 题目大意 给出三个长度为nnn的序列xi,yi,zix_i,y_i,z_ixi​,yi​,zi​&#xff0c;求一个序列aaa满足0≤ai<10970\leq a_i<10^970≤ai​<1097且 xi(∑j1iaj)yi(∑jinaj)≡zi(mod1097)x_i\lef…

IdentityServer4-客户端的授权模式原理分析(三)

在学习其他应用场景前&#xff0c;需要了解几个客户端的授权模式。首先了解下本节使用的几个名词Resource Owner&#xff1a;资源拥有者&#xff0c;文中称“user”&#xff1b;Client为第三方客户端&#xff1b;Authorization server为授权服务器&#xff1b;redirection URI&…

【做题记录】[NOIP2011 提高组] 观光公交

P1315 [NOIP2011 提高组] 观光公交 我们想在 \(k\) 次加速每一次都取当前最优的方案加速。 考虑怎样计算对于每一条边如果在当前情况下使用加速器能够使答案减少的大小。 如果当前到达某个点时已经有人在等待了&#xff0c;那么加速这个点以前的边能够让这个点下车的人距离减少…

[2019 牛客CSP-S提高组赛前集训营4题解] 复读数组(数论)+ 路径计数机(数上DP)+ 排列计数机(线段树+二项式定理)

文章目录T1&#xff1a;复读数组题目题解代码实现T2&#xff1a;路径计数机题目题解代码实现T3&#xff1a;排列计数机题目题解CODET1&#xff1a;复读数组 题目 有一个长为nk的数组&#xff0c;它是由长为n的数组A1,A2,…,An重复k次得到的。 定义这个数组的一个区间的权值为…

模板:(多重)哈希

前言 还在为不想写双哈希又怕哈希冲突挂掉发愁吗&#xff1f; 来这里&#xff0c;满足你的一切梦想&#xff01; 哈希还有模板&#xff1f; 其实就是把相关的函数和数组打包到一个结构体里 但是针心方便啊&#xff01;&#xff01;&#xff01; 如果想双哈希的话&#xff0c;定…

CF1183H Subsequences (hard version)

题意&#xff1a; 长度为n的字符串S&#xff0c;现在要找出k个不同的子序列&#xff0c;使得这些序列的总价值最低 一个序列的价值等于删去的字符长度&#xff08;空串也算子序列&#xff09; 1≤n≤100,1≤k≤1012 题解&#xff1a; 一看就是dp&#xff0c;我们先想想串a可…

P7888-「MCOI-06」Distinct Subsequences【dp】

正题 题目大意 给出一个长度为nnn的字符串aaa&#xff0c;求它的所有子序列的本质不同子序列个数。 1≤n≤1061\leq n\leq 10^61≤n≤106 解题思路 考虑每个子序列产生的贡献&#xff0c;为了防止算重我们一个只统计走子序列自动机上的边的子序列&#xff0c;也就是说对于TTT…

微软携手 Docker 打造 CNAB,分布式应用来了!

微软中国MSDN 前天Microsoft Connect(); 2018发布的众多最新科技&#xff0c;都让全球开发者惊艳不已。其中一项最令开发者瞩目并迫不及待——微软联合Docker发布了云本地应用捆绑包&#xff08;Cloud Native Application Bundle&#xff0c;以下简称CNAB&#xff09;&#xff…

9.4 模拟

前言 175分 60100150 T3和T4做的不好 T4没有理解题目的意思…qwq T3暴力似乎挂了… 但T1和T2还是不戳的 T1打表找规律的方法也许更为有效 考场 先看题。 药丸。。 T3、4甚至根本没有看懂… T1和T2也感觉挺玄乎的 有一种爆零的预感 8&#xff1a;10 先看T1 推了推似乎还是有…