poj 3368(RMQ)

题目链接 http://poj.org/problem?id=3368

这道题目是RMQ(Range Minimum/Maximum Query) 问题变形,寻找在区间内出现的最大频次。
用到动态规划
dp[ i] [j] =max(dp [i ] [j-1] ,dp[i +i<<(j-1) ] [j-1] ;

这道题的关键是如何构建一个dp数组。
我们可以将读取的数组num 变形。
所有相同的元素为 一组,用s[N]表示每组元素的起始下标,e[n]表示每组元素的结束下标,cnt【N】表示每组有多少个相同的元素。用pos[N]数组表示第 i 个元素属于第几个组。

     int id=1; //id表示有多少组
     s[1]=id;

     for(i=1;i<=n;i++)
     {
         pos[i]=id;
         cnt[id]++;
         if(num[i]!=num[i+1]||i==n)
         {
            e[id]=i; 
            id++;
            s[id]=i+1;
          }
      } 

完整代码。

#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
const int N=100010;
int cnt[N];
int pos[N];
int e[N];
int s[N];
int num[N];
int dp[N][20];
int pow[20];
int log2(int n)
{
  int cnt=0;
  while(n)
  {  cnt++;
     n>>=1;
   }
  return --cnt;
}
int max(int x,int y)
{  return x>y?x:y ; }

void RMQ(int n)
{
  for(int i=1;i<=n;i++ )
  {   
     dp[i][0]=cnt[i];
  }
  int temp=log2(n);
  for(int j=1;j<=temp;j++)
  {
    for(int i=1;i+pow[j]-1<=n;i++)
       dp[i][j]=max(dp[i][j-1],dp[i+pow[j-1]][j-1]);
  }
}
int getmax(int a,int b)
{
   int k=log2(b-a+1);
   return max(dp[a][k],dp[b-pow[k]+1 ][k] );
}
int main()
{
  int i,j,n,q;
  for(i=1,pow[0]=1;i<20;i++)
    pow[i]=2*pow[i-1];
  while (cin>>n&&n)
  {
     memset(cnt,0,sizeof(cnt) );
     cin>>q;
     for(i=1;i<=n;i++)
     {
         cin>>num[i];
     }
     int id=1;
     s[1]=id;

     for(i=1;i<=n;i++)
     {
         pos[i]=id;
         cnt[id]++;
         if(num[i]!=num[i+1]||i==n)
         {
            e[id]=i; 
            id++;
            s[id]=i+1;
          }
      } 
      RMQ(id);
      int x,y;
      while(q--)
      {
          scanf("%d%d",&x,&y);
          if(pos[x]==pos[y] ) // in the same group
          {
             cout<<y-x+1<<endl;
          }
          else 
          {
              int n1=e[pos[x]]-x+1;   
              int n2=y-s[pos[y]]+1;
              int n3=0;
              if( pos[y]-pos[x] >1)  //统计pos[x] 与pos[y] 之间的最大值。
              {  
                 n3=getmax( pos[x]+1,pos[y]-1 );
               }
              cout<<(  max( max(n1,n2) ,n3) )<<endl;
           }
     }
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值