博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[洛谷P4168] [Violet]蒲公英
阅读量:4876 次
发布时间:2019-06-11

本文共 3858 字,大约阅读时间需要 12 分钟。

写一篇博客纪念一下第一道AC的黑题~


题目链接

题目分析

神仙分块……做完之后感觉分块比我理解的要深刻很多啊

思路参考洛咕第一篇题解,特别巧妙


首先预处理两个数组:

\(s[i][j]\):前缀和,前\(i\)(含第\(i\)块)个块中\(j\)的出现次数

\(p[i][j]\):第\(i\)\(j\)个块的最小众数

如何预处理:

这一段题解写得比较略……可能是我太弱了,码了半天才从\(O(n^2)\)压成\(O(n \sqrt n)\)的,所以讲细一点

对于\(s[i][j]\)

第一层循环枚举\(i\),对于每个\(i\),先枚举\(j\)\(i - 1\)的总数转移过来,再扫描本块内的数并累加

对于\(p[i][j]\)

开一个辅助数组B,记录每个元素出现了多少次

第一层循环枚举\(i\),第二层循环枚举\(j\),第三层循环枚举块\(j\)内的每一个元素并累加,每一次\(i\)更改的时候清空B

如何询问:

分两种情况:

  • \(pos[r]-pos[l]<=1\),则暴力统计众数并返回答案
  • \(pos[r] - pos[l] >= 2\),则对于零散块内的每个元素,先将大块内的出现次数用\(s\)数组前缀和\(O(1)\)处理出来,再暴力统计零散块内的出现次数并更新答案,最后再和大块内的众数(\(p\)数组记录)比较一下即可

代码

#include
#define N (100000 + 5)#define int long long using namespace std;inline int read() { int cnt = 0, f = 1; char c = getchar(); while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();} while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();} return cnt * f;}int n, a[N], b[N], q, t, tmp = 10000000, gmax, m;int L[305], R[305], pos[N], s[305][N / 2], p[305][N / 2], t0;int ans, l, r;int B[N / 2];inline void Discretize () { sort (b + 1, b + n + 1); q = unique(b + 1, b + n + 1) - b - 1; for (register int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + q + 1, a[i]) - b;}inline void pre_work() { t = sqrt(n) + log(n)/log(2); t0 = n / t; for (register int i = 1; i <= t; ++i) { L[i] = (i - 1) * t0 + 1; R[i] = i * t0; } if (R[t] < n) { ++t; L[t] = R[t - 1] + 1; R[t] = n; } for (register int i = 1; i <= t; ++i) for (register int j = L[i]; j <= R[i]; ++j) pos[j] = i; for (register int i = 1; i <= t; ++i) { for (register int j = 1; j <= n; ++j) s[i][j] = s[i - 1][j]; for (register int j = L[i]; j <= R[i]; ++j) s[i][a[j]]++; } for (register int i = 1; i <= t; ++i) { memset(B, 0, sizeof(B)); tmp = 10000000, gmax = 0; for (register int j = i; j <= t; ++j) { for (register int k = L[j]; k <= R[j]; ++k) { B[a[k]]++; if (B[a[k]] >= gmax) { if (B[a[k]] > gmax) tmp = a[k]; else if (tmp > a[k]) tmp = a[k]; gmax = B[a[k]]; } } p[i][j] = tmp; } }} inline int query(int l, int r) { memset(B, 0, sizeof(B)); int ans = 50000, tmp = 0; int x = pos[l], y = pos[r]; if (x == y || x + 1 == y) { for (register int i = l; i <= r; ++i) { ++B[a[i]]; if (B[a[i]] > B[ans]) ans = a[i]; else if (B[a[i]] == B[ans] && a[i] < ans) ans = a[i]; } } else { for (register int i = l; i <= R[x]; ++i) { B[a[i]] = (s[y - 1][a[i]] - s[x][a[i]]); } for (register int i = L[y]; i <= r; ++i) { B[a[i]] = (s[y - 1][a[i]] - s[x][a[i]]); } for (register int i = l; i <= R[x]; ++i) { ++B[a[i]]; if (B[a[i]] > B[ans]) ans = a[i]; else if (B[a[i]] == B[ans] && a[i] < ans) ans = a[i]; } for (register int i = L[y]; i <= r; ++i) { ++B[a[i]]; if (B[a[i]] > B[ans]) ans = a[i]; else if (B[a[i]] == B[ans] && a[i] < ans) ans = a[i]; } tmp = p[x + 1][y - 1]; if (s[y - 1][tmp] - s[x][tmp] > B[ans]) ans = tmp; else if ((s[y - 1][tmp] - s[x][tmp] == B[ans]) && tmp < ans) ans = tmp; } return b[ans];}signed main() { n = read(), m = read(); for (register int i = 1; i <= n; ++i) a[i] = b[i] = read(); Discretize(); pre_work(); ans = 0; for (register int i = 1; i <= m; ++i){ l = read(); r = read(); l = (l + ans - 1) % n + 1, r = (r + ans - 1) % n + 1; if (l > r) swap(l, r); ans = query(l, r); printf("%lld\n", ans); } return 0;}

转载于:https://www.cnblogs.com/kma093/p/11167209.html

你可能感兴趣的文章
计算月初和月末,年初和年末的日期
查看>>
Linux内核中的中断
查看>>
以rem为单位根据移动设备的分辨率动态设置font-size
查看>>
Selenium2+python自动化61-Chrome您使用的是不受支持的命令行标记:--ignore-certificate-errors...
查看>>
system("x")
查看>>
thinkphp3.2.3分页
查看>>
python程序之profile分析
查看>>
分析与设计
查看>>
sklearn之validationcurve
查看>>
xfce4 没声音??
查看>>
nodejs 用express 访问mysql 并返回数据
查看>>
云计算之路-阿里云上:部分服务器未及时续费造成docker swarm集群故障
查看>>
properties 配置文件的读写
查看>>
Pytorch 报错总结
查看>>
GCD详细用法
查看>>
mongodb
查看>>
error MSB8031: Building an MFC project for a non-Unicode character set is deprecated
查看>>
多线程间通信之AutoResetEvent和ManualResetEvent的原理分析和开发示例
查看>>
新浪微博客户端(38)-显示键盘上的工具条
查看>>
NOIP前夕:codevs,解药还是毒药
查看>>