• 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
    ",ans);
        }
    }
  • 相关阅读:
    手动删除木马程序
    病毒注册表常用目标Svchost和Explorer
    对电脑假死现象的修复
    "添加与删除程序"报rundll32错误
    通过注册表regedit对Windows回收站进行恢复
    Win7的话,可能有十种简单的方法进行提速呢
    Windows死机的话,可能的一些猫病
    Android开发发布真机调试
    Java Web-----JSP与Servlet(一)
    Java——Log4j与Log4j2
  • 原文地址:https://www.cnblogs.com/tun117/p/5014181.html
Copyright © 2020-2023  润新知