zoukankan      html  css  js  c++  java
  • 排列

    描述

    2.排列

    (sum.cpp/c/pas)

    时间限制:1s

    内存限制:256MB

    【问题述】

    给出一个随机的排列,请你计算最大值减最小值的差小于等于0~n-1的区间分别有多少个。

    输入格式

    输入文件名为sum.in。

    第一行一个数T(<=10),表示数据组数

    对于每一组数据:

    第一行一个数n(1<=n<=100,000)

    第二行n个数a1...an,表示一个随机的排列

    【输出】

    输出文件名为sum.out。

    对于每组数据输出n行,分别表示差值小于等于0~n-1的区间个数

    【输入输出样例】

    sum.in

    sum.out

    1

    4

    3 2 4 1

    4

    5

    7

    10

    【数据说明】

    对于30%的数据,1<=n<=300;

    对于60%的数据,1<=n<=5000

    对于100%的数据,1<=n<=100000

    思路:

        暴力做法很简单,找出区间最大,最小值,再加到那个值所对应的数组中,最后求前缀和就行了。

      但跑得太慢了。因为数据是随机的,所以最大值和最小值变化的频率并不高,

      也就是说,那个最大值和最小值的差是一段一段的(A,A,A,A,A,B,B,B,B,C,C这种样子)。

      这样的话,只需要找出每段区间的长度,然后把长度加到ans里就行了。

      在这里维护一个单调栈,站里记录单调序列元素的位置(也就是每段连续区间的端点)。

      这样就实现了每下都能走一段连续区间,降低了复杂度。(因为不用一个一个的走了)。

    #include<iostream>
    #include<queue>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N=100100;
    long long  ans[N];
    int a[N],mnn[N],mxn[N];
    int t,n,cnt1,cnt2;
    void PUSH(int x)
    {
        mxn[++cnt1]=x;
        while(cnt1>1&&a[mxn[cnt1-1]]<a[mxn[cnt1]])
            cnt1--,mxn[cnt1]=mxn[cnt1+1];
        
        mnn[++cnt2]=x;
        while(cnt2>1&&a[mnn[cnt2-1]]>a[mnn[cnt2]])
            cnt2--,mnn[cnt2]=mnn[cnt2+1];    
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            memset(ans,0,sizeof(ans));
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            ans[0]=n;
            cnt1=cnt2=0;
            mxn[++cnt1]=mnn[++cnt2]=n;
            for(int L=n-1;L>=1;L--)
            {
                PUSH(L);
                int last=n+1,x=1,y=1,now;
                while(mxn[x]!=mnn[y])
                {
                    now=max(mxn[x],mnn[y]);
                    ans[a[mxn[x]]-a[mnn[y]]]+= 1LL*(last-now);
                    last=now;
                    if(mxn[x]>mnn[y])    x++;
                    else y++;
                }
            }
            for(int i=1;i<n;i++)
                ans[i]+=ans[i-1];
            for(int i=0;i<n;i++)
                printf("%lld
    ",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    UVA1349 Optimal Bus Route Design 最优巴士路线设计
    POJ3565 Ants 蚂蚁(NEERC 2008)
    UVA1663 Purifying Machine 净化器
    UVa11996 Jewel Magic 魔法珠宝
    NEERC2003 Jurassic Remains 侏罗纪
    UVA11895 Honorary Tickets
    gdb调试coredump(使用篇)
    使用 MegaCLI 检测磁盘状态并更换磁盘
    员工直接坦诚直来直去 真性情
    山东浪潮超越3B4000申泰RM5120-L
  • 原文地址:https://www.cnblogs.com/CLGYPYJ/p/7620008.html
Copyright © 2011-2022 走看看