游程编码的基本原理是:用一个符号值或串长代替具有相同值的连续符号(连续符号构成了一段连续的“行程”。游程编码因此而得名),使符号长度少于原始数据的长度。只在各行或者各列数据的代码发生变化时,一次记录该代码及相同代码重复的个数,从而实现数据的压缩。
游程编码(Run Length Encoding , RLE)
例如:5555557777733322221111111
游程编码为:(5,6)(7,5)(3,3)(2,4)(1,7)
解题思路很好:
用value[i] count[i] 分别表示 第i段的数值 和 出现次数;
num[p] left[p] right[p]分别表示位置p所在段的编号和左右端点的位置。
每次查询(left,right)的结果为以下三个部分的最大值:从left到left所在段结束处的元素个数、从right所在段开始到right处的元素个数、中间第num[left]+1段到第num[right]-1段的count的最大值。
特殊情况:如果left和right在同一段中,答案是R-L+1。
解决方法如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100001; int n,q; int d[maxn][35]; int a[maxn]; int value[maxn],count_[maxn]; int num[maxn],left[maxn],right[maxn]; void RMQ_int(){ for(int i=0;i<n;i++) d[i][0]=count_[i]; for(int j=1; (1<<j)<=n; j++) for(int i=0; i+(1<<j)-1<n; i++) d[i][j]=max(d[i][j-1],d[i+(1<<j-1)][j-1]); } int RMQ(int L,int R){ int k=0; while((1<<(k+1))<=(R-L+1)) k++; return max(d[L][k],d[R-(1<<k)+1][k]); } int main() { while(scanf("%d",&n)!=EOF){ if(n==0) break; scanf("%d",&q); memset(count_,0,sizeof(count_)); memset(num,0,sizeof(num)); memset(left,0,sizeof(left)); memset(right,0,sizeof(right)); memset(d,0,sizeof(d)); for(int i=0;i<n;i++) scanf("%d",&a[i]); int temp = a[0]; int t=0; value[t]=temp;count_[t]++; num[0]=t;left[0]=0; for(int i=1;i<n;i++){ if(a[i]==temp){ count_[t]++; num[i]=t;left[i]=left[i-1]; } else{ for(int j=left[i-1];j<i;j++){ right[j]=i-1; } temp = a[i]; t++; value[t] = temp;count_[t]++; num[i]=t;left[i]=i; } } t++; for(int i=left[n-1];i<n;i++){ right[i]=n-1; } RMQ_int(); int left_,right_; int ans=0; for(int i=0;i<q;i++){ scanf("%d%d",&left_,&right_); left_--;right_--; if(num[left_]==num[right_]) ans=right_-left_+1; else{ ans=max(right[left_]-left_+1,right_-left[right_]+1); if(num[left_]+1 > num[right_]-1) ans=max(ans,0); else{ ans=max(ans,RMQ(num[left_]+1,num[right_]-1)); } } printf("%d\n",ans); } } return 0; }
时间: 2024-10-14 04:51:03