题解子数组有主元素
Posted kcn999
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解子数组有主元素相关的知识,希望对你有一定的参考价值。
题目描述
一个数组B,如果有其中一个元素出现的次数大于length(B) div 2,那么该元素就是数组B的主元素,显然数组B最多只有1个主元素,因为数组B有主元素,所以被称为“优美的”。
给出数组A[0..n-1],问数组A有多少个“优美的”子数组。数组A的子数组是由数组A的连续若干个元素构成的数组。数组A不是直接给出的,而是通过如下公式自动产生的:
for i = 0 to n-1 do { A[i] = (seed div 2^16) % m seed = (seed * 1103515245 + 12345) % 2^31 }
如上公式中: n, seed, m都是输入数据给出的,div是表示整数的整除。^是表示幂运算。
输入输出格式
输入格式
一行,3个整数,n, seed, m。1 <= n <= 100000。 0 <= seed <= 2^31-1。 1 <= m <= 50。
输出格式
一个整数。
输入输出样例
输入样例一
5 200 5
输出样例一
8
输入样例二
10 15 3
输出样例二
23
输入样例三
8 12345678 1
输出样例三
36
输入样例四
27 541 50
输出样例四
27
题解
观察此题,$m$很小,我们可以从这里入手。
枚举$[0,m]$中的$i$,设$d[j]$为$[1,j]$中$a$数组内元素$i$的数量,$d[0]=0$,那么很容易想到,如果$[l,r]$有主元素,那么$d[r]-d[l-1]>0$即$d[r]>d[l-1]$。
此时我们可以设$s[k]$为$[1,j]$中$d$数组内元素$k$的数量,用树状数组等维护一下即可,这样就可以用$O(mnlogn)$的时间复杂度通过这题了。
#include <iostream> #include <cstdio> #include <cstring> #define MAX_N (100000 + 5) #define lowbit(x) ((x) & -(x)) using namespace std; int n; int a[MAX_N]; int seed, m; const int pow2_16 = 1 << 16; const long long pow2_32 = 1ll << 31; int d[MAX_N]; int s[MAX_N + MAX_N]; long long ans; int main() { scanf("%d%d%d", &n, &seed, &m); for(register int i = 1; i <= n; ++i) { a[i] = (seed / pow2_16) % m; seed = (seed * 1103515245ll + 12345) % pow2_32; } for(register int i = 0; i < m; ++i) { d[0] = 0; memset(s, 0, sizeof s); for(register int j = n + 1; j <= n + n + 1; j += lowbit(j)) { ++s[j]; } for(register int j = 1; j <= n; ++j) { if(a[j] == i) d[j] = d[j - 1] + 1; else d[j] = d[j - 1] - 1; for(register int k = d[j] + n; k; k -= lowbit(k)) { ans += s[k]; } for(register int k = d[j] + n + 1; k <= n + n + 1; k += lowbit(k)) { ++s[k]; } } } printf("%lld", ans); return 0; }
以上是关于题解子数组有主元素的主要内容,如果未能解决你的问题,请参考以下文章
精选力扣500题 第29题 LeetCode 53. 最大子序和c++ / java 详细题解