CodeForces 602D 【单调队列】【简单数学】

题意:

给你n个数,m次询问,每次询问给l和r代表l和r中间所有子区间中特征值的和。

特征值的定义是在这个区间中找i和j使得|tmp[i]-tmp[j]|/|j-i|最大。

思路:

首先是特征值的定义,这个东西其实是斜率~不知道从哪里看到的证明,这个只有相邻的点才可能最大。所以给定区间找到最大值其实是在相邻的中找。这是这题第一个关键点。

如果一个一个加寻找每一个区间那么复杂度应该是n^2,这里的n大小是1e5,还是不行。然后这个时候思路就是通过单调队列来解决啦~【个人认为更像是个DP】找到某个点左边和右边能扩展的最大覆盖值~然后我们可以计算出从左边到右边对于这个点他本身能分离出来的子区间的数量。【就是个简单的组合问题,从左边中选一个起点从右边选一个终点】,然后用子区间的数量乘上该点(不应该说成点,应该是相邻两个点之间的斜率)。屌丝一开始在这里被坑了...加入某两个值相等了怎么办...这个地方是坑点,不能重复也不能缺漏...当相同的时候只向左边扩展或者只向右边扩展...因为计算的时候我们每个点都是要进行计算的,如果同时扩展范围肯定会重复,如果都不扩展那么会丢失包含两个相同最大值的子区间。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100500
using namespace std;
int n,m;
int tmp[N];
int ttmp[N];
int l[N],r[N];
int main()
{
    int s,e;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&tmp[i]);
    }
    for(int i=1;i<n;i++)
    {
        ttmp[i]=max(tmp[i],tmp[i+1])-min(tmp[i],tmp[i+1]);
    }
    /*for(int i=1;i<=n;i++)
    {
        printf("%d ",ttmp[i]);
    }
    puts("");*/
    for(int i=1;i<n;i++)
    {
        l[i]=1;
        for(int j=i-1;j>=1;)
        {
            if(ttmp[i]>ttmp[j])
            {
                l[i]+=l[j];
                j-=l[j];
            }
            else
            {
                break;
            }
        }
    }
    /*for(int i=1;i<n;i++)
    {
        printf("%d ",l[i]);
    }
    puts("");*/
    for(int i=n-1;i>=1;i--)
    {
        r[i]=1;
        for(int j=i+1;j<n;)
        {
            if(ttmp[i]>=ttmp[j])
            {
                r[i]+=r[j];
                j+=r[j];
            }
            else
            {
                break;
            }
        }
    }
    /*for(int i=1;i<n;i++)
    {
        printf("%d ",r[i]);
    }
    puts("");*/
    long long ans;
    for(int i=1;i<=m;i++)
    {
        ans=0;
        scanf("%d%d",&s,&e);
        for(int j=s;j<e;j++)
        {
            long long ll=min(j-s+1,l[j]);
            long long rr=min(e-j,r[j]);
            ans+=(ll*rr*ttmp[j]);
        }
        printf("%I64d\n",ans);
    }
}
时间: 2024-07-30 13:52:04

CodeForces 602D 【单调队列】【简单数学】的相关文章

CodeForces - 91B单调队列

有一个数列,对于每一个数,求比它小的在他右边距离他最远的那个数和他的距离 用单调队列做,维护单调队列时可采用如下方法,对于每一个数,如果队列中没有数,则加入队列,如果队列头的数比当前数大,则舍弃该数 对于此题,可用两个队列来维护,一个保存值,一个保持位置,每次查询对值进行二分,然后到对应保持位置的队列中求出结果 #include<map> #include<set> #include<cmath> #include<queue> #include<st

HUD 3706 单调队列简单题

Problem Description Give you three integers n, A and B. Then we define Si = Ai mod B and Ti = Min{ Sk | i-A <= k <= i, k >= 1} Your task is to calculate the product of Ti (1 <= i <= n) mod B. 不描述题意了,三行英文挺明了的,今天刚学单调队列,自己模拟一下过了这题 单调队列 1,永远保持队

Strip CodeForces - 487B (单调队列)

题面: Alexandra has a paper strip with n numbers on it. Let's call them ai from left to right. Now Alexandra wants to split it into some pieces (possibly 1). For each piece of strip, it must satisfy: Each piece should contain at least l numbers. The di

poj2823_单调队列简单入门

题目链接:http://poj.org/problem?id=2823 #include<iostream> #include<cstdio> #define M 1000001 using namespace std; int n,k; int a[M]; int q[M]; int p[M]; void get_min() { int head=1; int tail=0; for(int i=0;i<k-1;i++) { while(head<=tail&

【算法学习笔记】53.单调队列的简单应用 SJTU OJ 1034 二哥的金链

1034. 二哥的金链 Description 一个阳光明媚的周末,二哥出去游山玩水,然而粗心的二哥在路上把钱包弄丢了.傍晚时分二哥来到了一家小旅店,他翻便全身的口袋也没翻着多少钱,而他身上唯一值钱的就是一条漂亮的金链.这条金链散发着奇异的光泽,据说戴上它能保佑考试门门不挂,RP++.好心的老板很同情二哥的遭遇,同意二哥用这条金链来结帐.虽然二哥很舍不得这条金链,但是他必须用它来付一晚上的房钱了. 金链是环状的,一共有 N 节,老板的要价是 K 节.随便取下其中 K 节自然没问题,然而金链上每一

Codeforces Round #189 (Div. 1) B. Psychos in a Line 单调队列

B. Psychos in a Line Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/319/B Description There are n psychos standing in a line. Each psycho is assigned a unique integer from 1 to n. At each step every psycho who h

简单数据结构总结——单调队列

单调队列一般是具有单调性的队列废话 视具体题目而定,单调队列有单调递增和单调递减两种,一般来讲,队列的队首是整个队列的最大值或最小值 单调队列可以解决许多问题,而且可以用来优化DP,但是这里不讲因为我还不会' 下面简单的介绍一下单调队列的实现 具体步骤: 若队列为空,将A[i]从队尾入队 若队列不为空,将比A[i]大的元素都从队尾弹出,然后把A[i]入队 若队列不为空且A[i]大于队尾,则直接从队尾把A[i]入队 实现一般采用双端队列主要因为好写当然也可以自己手写 下面放出代码 1 if(q.e

codeforces 251A Points on Line(二分or单调队列)

Description Little Petya likes points a lot. Recently his mom has presented him n points lying on the line OX. Now Petya is wondering in how many ways he can choose three distinct points so that the distance between the two farthest of them doesn't e

CodeForces 15D Map 单调队列优化

两次单调队列求出每个子矩阵的最小值,区间减法求出每个子矩阵的和,然后丢到优先队列里跑出来就好了. 写锉了,加了读入挂才过. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack&g