HDU - 5875 Function(单调栈)

题目链接:点击查看

题目大意:给出一段连续数列,在给出m个询问,要求按照给出的函数查询得到结果

题目分析:第一眼一看题目会觉得是个递归题目,但是盲目递归肯定会TLE,所以我们要分析这个题目到底要干什么,这个题目其实就是问在闭区间[l,r]内,一开始数字为a[l],然后依次对a[l+1]到a[r]取模,即连续取模,分析了半天发现也没有什么性质,但是却发现了一个小技巧,就是当一个数取模时,如果模比这个数要大的话,那对这个数是没有影响的,只有当模小于等于这个数的时候取模才是有意义的,所以我们可以将连续取模优化为每次找到一个比当前结果要小于等于的数再进行取模,类似于跳着取模,这样就能将时间复杂度大大降低,所以我们可以用线段树来存储区间内的最小值,这样在查询的时候就可以优先查询左区间,这样就可以同时满足“第一个”和“比当前数字小”这两个条件了。不过我线段树还是菜啊,自己埋着头调了一个小时也没调好那个查询函数,总是有点小bug,转念一想,想起来好像就是要查找右边第一个小的数字,那么能不能用单调栈莽一下,因为单调栈的主要用处就是用o的时间复杂度来存储左边或右边第一个比当前数字大或小的位置,有了这样一个剪枝,虽然最后每次取模的次数相对于线段树来说会增多,但相对于暴力比较来说还是快了不少呢,毕竟也是跳着取模。。而且最后事实也说明了,数据没有那种特别恶心的,单调栈跑出来的还是比线段树快啊,因为单调栈的时间复杂度是n,此后查询时间复杂度就变为了1,这样在遍历一遍每个区间,总的时间复杂度稍大于n+m吧,因为每次查询虽然是要跳着查询,但还是会找很多次。。但线段树的话,建树nlogn,每次查询也是logn,最坏的查询也是logn*logn,所以时间复杂度是nlogn+nlogn*logn,搭眼一看,一般数据来说肯定是单调栈更快一点,但是特殊数据可能会卡。。不过谢天谢地这个题目没有出那种恶心人的数据。

直接上代码了,单调栈好久没用了,从网上复制的板子:

#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
typedef long long LL;
 
const int inf=0x3f3f3f3f;
 
const int N=1e5+100;

int a[N];

int id[N];

int main()
{
//    freopen("input.txt","r",stdin)
    int w;
    cin>>w;
    while(w--)
    {
        int n,m;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        stacks;
        for(int i=n;i>=1;i--)
        {
            while(!s.empty()&&a[s.top()]>a[i])//单调栈
            {
                s.pop();
            }
            if(s.empty())
                id[i]=-1;
            else
                id[i]=s.top();
            s.push(i);
        }
        scanf("%d",&m);
        while(m--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==y)
            {
                printf("%d\n",a[x]);
            }
            else
            {
                int ans=a[x];
                while(1)
                {
                    int pos=id[x];
                    if(pos==-1||pos>y)
                        break;
                    ans%=a[pos];
                    x=pos;
                }
                printf("%d\n",ans);
            }
        }
    }
    
    
    
    return 0;
}

 

你可能感兴趣的:(单调栈/单调队列,单调栈)