超詳しい解説#C. 最も多く出現する数値(POJ3368の最頻値)

トピック


一連の考え

分析する

この問題は要素の出現数を累積して間隔の最大値を求めることができるため、 STを使用して解くことができますmx[i][j]は区間 [i. 2^j-1]最大値を表し区間の長さは2^jです

アルゴリズムのステップ

1.

非減少シーケンス等しい要素は隣接している必要があり各要素は要素と比較され繰り返し回数が累積されてmx[i][0]に保存されます。

2.

ST テーブルを作成します

3.

区間 [1,r]最大値を問い合わせます最初の数値が前の数値と等しい場合は、まずクエリ間隔[l, r]内の最初の数値出現数をカウントし、次に残りの間隔の最大値をクエリし、次に2 つの数値の最大値を計算します。 。

詳細

たとえば、次の例を見てみましょう。

1. 初期化

入力サンプル内の要素の出現数を累積してmx[i][0]に保存します

for(int i = 1; i <= n; i++)
{
  scanf("%lld",&a[i]);
  if(a[i] == a[i - 1]) mx[i][0] = mx[i - 1][0] + 1;
  else mx[i][0] = 1;
}

2. ST を作成します

void zynb()
{
  int r = log2(n);
  for(int i = 1; i <= r; i++)
    for(int j = 1; s[i] + j - 1 <= n; j++)
      mx[j][i] = max(mx[j][i - 1],mx[j + s[i - 1]][i - 1]);
}

3.クエリ。

最初のクエリの例は 2 3 です。

区間 [2, 3] 内の最も頻繁に発生する値の出現数をクエリします。まず、a [2] = a [1]、t++、つまり t = 3 であるため、t = l = 2、このとき a [3] ≠ a [2]、t - l = 1、RMQ(t , r) = RMQ(3, 3) = 1 の場合、2 つの最大値を見つけ、[2, 3] 区間で最も頻繁に発生する値の出現数が 1 であることを取得します。注: RMQ(2, 3) を直接クエリすることはできません。

2 番目のクエリの例は 1 10 です。

区間 [1, 10] 内の最も頻繁に発生する値の出現数をクエリします。まず、 t = l =1 、 a [1] ≠ a [0] 、 t - l =0 、 RMQ(t ,r)=RMQ(1,10)=4、2 つの最大値を見つけて、[1 を取得します。 , 10] 区間内での最も頻繁な値の出現数は 4 です。

3 番目のクエリの例は 5 10 です。

查询[5, 10]区间最频繁值的出现次数。首先,t = l =5,因为a [5] = a [4],t ++,即t =6;a[6] = a [5],t++,即t =7;此时a [7]≠a [6],t -l =2,RMQ(t , r )=RMQ(7,10)=3,求两者的最大值,得到[5, 10]区间最频繁值的出现次数为3。

若直接查询RMQ(5, 10)=4,但是a [5]在[5, 10]区间的出现次数是2,则不是4。因此若a [l]和前一个数a [l -1]相等,则需要先统

计a [l ]在[l , r ]区间的出现次数,再查询剩余区间的最值,比较

两者的最大值。

int weqsb(int x,int y)
{
  if(x > y) return 0;
  int r = log2(y - x + 1);
  int t1 = max(mx[x][r],mx[y - s[r] + 1][r]);
  return t1;
}

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int s[10000001],n,q,a[10000001],mx[100001][101],t,l,r,ans;
void zynb()
{
  int r = log2(n);
  for(int i = 1; i <= r; i++)
    for(int j = 1; s[i] + j - 1 <= n; j++)
      mx[j][i] = max(mx[j][i - 1],mx[j + s[i - 1]][i - 1]);
}
int weqsb(int x,int y)
{
  if(x > y) return 0;
  int r = log2(y - x + 1);
  int t1 = max(mx[x][r],mx[y - s[r] + 1][r]);
  return t1;
}
signed main()
{
  s[0] = 1;
  for(int i = 1; i <= 60; i++) s[i] = s[i - 1] * 2;
  while(1)
  {
    memset(mx,0,sizeof(mx));
    scanf("%lld",&n);
    if(n == 0) break;
    scanf("%lld",&q);
    for(int i = 1; i <= n; i++) mx[i][0] = 1;
    for(int i = 1; i <= n; i++)
    {
      scanf("%lld",&a[i]);
      if(a[i] == a[i - 1]) mx[i][0] = mx[i - 1][0] + 1;
      else mx[i][0] = 1;
    }
    zynb();
    while(q--)
    {
      scanf("%lld%lld",&l,&r);
      t = l;
      while(t <= r && a[t] == a[t - 1]) t++;
      printf("%lld\n",max(weqsb(t,r),t - l));
    }
  }
  return 0;
}

おすすめ

転載: blog.csdn.net/weq2011/article/details/128767599