NYOJ 119 士兵杀敌(三)(RMQ)

士兵杀敌(三)

时间限制:2000 ms  |  内存限制:65535 KB
难度:5
 
描述 南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果。 所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少。 现在,请你写一个程序,帮小工回答南将军每次的询问吧。 注意,南将军可能询问很多次。
输入 只有一组测试数据
第一行是两个整数N,Q,其中N表示士兵的总数。Q表示南将军询问的次数。(1<N<=100000,1<Q<=1000000)
随后的一行有N个整数Vi(0<=Vi<100000000),分别表示每个人的杀敌数。
再之后的Q行,每行有两个正正数m,n,表示南将军询问的是第m号士兵到第n号士兵。
输出 对于每次询问,输出第m号士兵到第n号士兵之间所有士兵杀敌数的最大值与最小值的差。   样例输入 5 2
1 2 6 9 3
1 2
2 4
  样例输出 1

7


【思路分析】

   一个简单的求区间最值的问题,可以用线段树解决,这里为了学习一下RMQ算法就用RMQ写了代码。以下大致写一写我对RMQ算法的理解:

   RMQ(Range Minimum/Maximum Query),即区间最值查询,用到了二分以及动归的思想。其预处理的效率为O(nlogn),查询的效率为O(1),所以能够较高效地解决区间最值的查询问题。

   其具体操作为:

   一、预处理:设A[i]是要求区间最值的数列,F[i][j]表示从第i个数起连续2^j个数中的最值。(DP的状态)例如对于A[5] = {1,5,4,2,3},F[1][0]表示从第1个数起连续2^0个数中的最值,即从第1个数起连续1个数中的最值,也就是1这个数,同理,F[2][0] = 5,F[3][0] = 4。。。。。。所以F[i][0] = A[i](i从1开始)(DP的初始值)。找到了DP的状态以及初始值,最后就是找状态转移方程。把F[i][j]平均分为两段,即从i到i + 2 ^ (j - 1) - 1为一段,从i + 2 ^ (j - 1)到i + 2^j - 1为另一段,每一段的长度为2 ^ (j - 1),所以根据二分的思想,F[i][j]的值也就是等于这两段的最值的最值,可以得到状态转移方程为F[i][j] = max(F[i][j - 1],F[i + 2 ^ (j - 1)][j - 1])(假设要求的F为最大值),这样就完成了预处理的操作,注意在处理次幂时用位运算来提高速度。

  二、查询:对于给出的要求查询的区间[src,des],首先我们要找的就是这个区间的中间位置,令k = (log(des - src + 1)) / log(2),则k就是这个中间位置,经过预处理后各个区间的最值都存在F这个二维数组内,所以可以直接查询出来,即ans = max(F[src][k],F[des - 2 ^ k + 1][k]),这里还是假设要求的是区间最大值。


代码如下:

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#define maxn 10005
using namespace std;
int maxSum[maxn][20], minSum[maxn][20];

void RMQ(int num)    //预处理->O(nlogn)
{
   for(int j = 1;j < 20;j++)
   {
       for(int i = 1;i <= num;i++)
       {
           if((i + (1 << j) - 1) <= num)//区间长度要满足总数条件
           {
               maxSum[i][j] = max(maxSum[i][j - 1],maxSum[i + (1 << (j - 1))][j - 1]);
               minSum[i][j] = min(minSum[i][j - 1],minSum[i + (1 << (j - 1))][j - 1]);
           }
       }
   }
}

int main()
{
    int num,query;
    int src,des;
    scanf("%d %d",&num,&query);
    for(int i = 1;i <= num;i++)
    {
        scanf("%d",&maxSum[i][0]);//表示从第i个数起连续2^0(1)个数,即就是这第i个数
        minSum[i][0] = maxSum[i][0];
    }
    RMQ(num);
    while(query--)//O(1)查询
    {
        scanf("%d %d",&src,&des);
        int k = (int)(log(des - src + 1.0) / log(2.0));//中间位置
        int ansMax = max(maxSum[src][k],maxSum[des - (1 << k) + 1][k]);
        int ansMin = min(minSum[src][k],minSum[des - (1 << k) + 1][k]);
        printf("%d\n",ansMax - ansMin);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
综合小区管理系统管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、车位管理、车位分配管理、出入管理、字典管理、房屋管理、物业费缴纳管理、公告管理、物业人员投诉管理、我的私信管理、物业人员管理、用户管理、管理员管理。用户的功能包括管理部门以及部门岗位信息,管理招聘信息,培训信息,薪资信息等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 综合小区管理系统管理系统可以提高综合小区管理系统信息管理问题的解决效率,优化综合小区管理系统信息处理流程,保证综合小区管理系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理综合小区管理系统信息,包括出入管理,报修管理,报修管理,物业费缴纳等,可以管理操作员。 出入管理界面,管理员在出入管理界面中可以对界面中显示,可以对招聘信息的招聘状态进行查看,可以添加新的招聘信息等。报修管理界面,管理员在报修管理界面中查看奖罚种类信息,奖罚描述信息,新增奖惩信息等。车位管理界面,管理员在车位管理界面中新增。公告管理界面,管理员在公告管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值