Beyond the Void
BYVoid
pku 3368 Frequent values
本文正體字版由OpenCC轉換

離散化+RMQ問題。首先讀入序列A,把序列中元素離散化到B,存儲值相同的元素的個數,以及每個值第一次在A中出現的位置Start[i]。然後對序列B進行SparseTable預處理(ST算法)。對於每個詢問,求[x,y]之間最頻繁出現的值的個數,算出x,y對應的序列B中位置a,b。然後根據a,b大小的不同,分三種情況考慮。

  • 若a與b相等,則詢問的區間[x,y]值全部相同,結果就是y-x+1。
  • 若a+1=b,則[x,y]恰好跨兩個值的區間,結果就是兩個值的個數的較大值Max(Start[b]-x,y-Start[b]+1)。
  • 若a+1<b,則[x,y]跨多個值,則最大值除了在兩邊意外,還可能會是B[a+1..b-1]中的最大值,用處理好的SparseTable求序列B中[a+1,b-1]的最大值即可。
/* 
 * Problem: pku3368 Frequent values
 * Author: Guo Jiabao
 * Time: 2009.4.1 19:30
 * State: Solved
 * Memo: RQM SparseTable
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
const int MAXN=100001,LG=18,INF=0x7FFFFFFF;
using namespace std;
int M,N,Q;
int A[MAXN],Map[MAXN],F[MAXN][LG],Start[MAXN],Log[MAXN];
void init()
{
	int i,k;
	freopen("frequent.in","r",stdin);
	freopen("frequent.out","w",stdout);
	A[N=0]=INF;
	for (i=1,k=0;i<MAXN;i++)
	{
		if (1<<(k+1)<=i)
			k++;
		Log[i]=k;
	}
}
bool readfile()
{
	scanf("%d",&M);
	if (M==0) return false;
	scanf("%d",&Q);
	for (int i=1;i<=M;i++)
	{
		scanf("%d",&A[i]);
		if (A[i]!=A[i-1])
		{
			Map[i]=++N;
			Start[N]=i;
			F[N][0]=1;
		}
		else
		{
			Map[i]=N;
			F[N][0]++;
		}
	}
	return true;
}
inline int Max(int a,int b){return a>b?a:b;}
void SpraseTable()
{
	int i,j,jt;
	for (j=jt=1;jt<=N;j++,jt=jt<<1)
	{
		for (i=1;i+jt<=N;i++)
		{
			F[i][j]=Max(F[i][j-1],F[i+jt][j-1]);
		}
	}
}
void Query()
{
	int i,ta,tb,a,b,k,tk,Ans;
	for (i=1;i<=Q;i++)
	{
		scanf("%d%d",&ta,&tb);
		a=Map[ta];b=Map[tb];
		if (a==b)
			Ans=tb-ta+1;
		else if (b==a+1)
			Ans=Max(Start[b]-ta,tb-Start[b]+1);
		else
		{
			Ans=Max(Start[a+1]-ta,tb-Start[b]+1);
			a++;b--;
			k=Log[b-a+1];
			tk=1<<k;
			Ans=Max(Ans,F[a][k]);
			Ans=Max(Ans,F[b-tk+1][k]);
		}
		printf("%dn",Ans);
	}
}
int main()
{
	init();
	while (readfile())
	{
		SpraseTable();
		Query();
	}
}

上次修改時間 2017-02-03

相關日誌