码迷,mamicode.com
首页 > 其他好文 > 详细

P5048 [[Ynoi2019模拟赛]Yuno loves sqrt technology III]

时间:2019-11-12 16:15:30      阅读:89      评论:0      收藏:0      [点我收藏+]

标签:using   size   位置   指针   inline   line   ++   sign   ==   

为什么我感觉这题难度虚高啊……

区间众数的出现次数…

计算器算一下 \(\sqrt 500000 = 708\)

然后我们发现这题的突破口?

考虑分块出来[L,R]块的众数出现个数 用 \(\texttt{mx[L][R]}\) 维护就可以了

每次考虑一个L… 然后R指针一直向右移不断的更新到N 这样子做的复杂度因为最多有 \(\sqrt n\) 个块 所以复杂度大概是 \(n\sqrt n\) 实际上还少一点…

然后整块的想好了……单独的怎么处理?

分类讨论

1 \(\texttt{L}\)\(\texttt{R}\) 所在的块相同 那么分块的常规暴力操作(记得清空…)复杂度保证是 \(\sqrt n\)

2 不在一个块的话 考虑用一种其他方法…记录一个\(\texttt{v[i]}\)存的是每个 数值 i 的出现位置 再记录一个 \(\texttt{pos[i]}\) 表示 i 这个数值在序列里是第几次出现…(主要还是方便vector的操作…)
您已经统计出来了 \(\texttt{L-R}\) 的最多次数 肯定是保底 \(\texttt{mx[L][R]}\) 了 根据这个基础 这样指针移动就相对来说保证了复杂度…每次也是\(\sqrt n\)

讲下具体操作 记录了这个 \(pos_i\) 是 i 在 \(a_i\) 第几个出现 然后 \(v_{a_i}\)是记录了每个 \(a_i\)的出现位置 于是就可以 在左半区间的时候判断是否\(\leq \texttt{R}\) 在右半区间的时候判断是否\(\ge\texttt{L}\) 如果满足条件就加大 当前的\(\texttt{ans}\) 直到不满足 肯定是最优的…

#include<bits/stdc++.h>
using namespace std ;
const int N = 5e5 + 10 ;
int n , m , a[N] , b[N] , bl[N] , unt = 0 , L[710] , R[710] , mx[710][710] , tot[N] , pos[N] ;
vector < int > v[N] ;
inline int query(int l , int r) { int ans = 0 ;
  if(bl[l] == bl[r]) {
    for(register int i = l ; i <= r ; i ++) tot[a[i]] = 0 ;
    for(register int i = l ; i <= r ; i ++) ans = max(ans , ++ tot[a[i]]) ;
    return ans ;
  } ans = mx[bl[l] + 1][bl[r] - 1] ;
  for(register int i = l ; i <= R[bl[l]] ; i ++) {
    int it = pos[i] ; while(it + ans < v[a[i]].size() && v[a[i]][it + ans] <= r) ++ ans ;
  }
  for(register int i = L[bl[r]] ; i <= r ; i ++) {
    int it = pos[i] ; while(it - ans >= 0 && v[a[i]][it - ans] >= l) ++ ans ;
  } return ans ;
}
signed main() {
  // freopen("0.in" , "r" , stdin) ;
  ios :: sync_with_stdio(false) ;
  cin.tie(0) ;cout.tie(0) ;
  cin >> n >> m ;
  for(register int i = 1 ; i <= n ; i ++) { cin >> a[i] ; b[i] = a[i] ; }
  sort(b + 1 , b + n + 1) ;
  int len = unique(b + 1 , b + n + 1) - b - 1 ;
  for(register int i = 1 ; i <= n ; i ++) { a[i] = lower_bound(b + 1 , b + len + 1 , a[i]) - b ; }
  for(register int i = 1 ; i <= n ; i ++) { v[a[i]].push_back(i) ; pos[i] = v[a[i]].size() ; pos[i] -- ; }
  int unt = sqrt(n) ;
  for(register int i = 1 ; i <= n ; i ++) bl[i] = (i - 1) / unt + 1 ;
  for(register int i = 1 ; i <= bl[n] ; i ++) { L[i] = (i - 1) * unt + 1 ; R[i] = i * unt ; }
  R[bl[n]] = n ;
  for(register int i = 1 ; i <= bl[n] ; i ++) {
    memset(tot , 0 , sizeof(tot)) ;
    for(register int j = i ; j <= bl[n] ; j ++){
      mx[i][j] = mx[i][j - 1] ;
      for(register int k = L[j] ; k <= R[j] ; k ++) mx[i][j] = max(mx[i][j] , ++ tot[a[k]]) ;
    }
  }
  int lastans = 0 ;
  for(register int i = 1 ; i <= m ; i ++) {
    int l , r ; cin >> l >> r ;
    l ^= lastans ; r ^= lastans ;
    if(l > r) swap(l , r) ;
    cout << (lastans = query(l , r)) << '\n' ;
  }
  return 0 ;
}

P5048 [[Ynoi2019模拟赛]Yuno loves sqrt technology III]

标签:using   size   位置   指针   inline   line   ++   sign   ==   

原文地址:https://www.cnblogs.com/Isaunoya/p/11842586.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!