2013蓝桥杯省赛B组-连号区间数

题面

题目描述
小明这些天一直在思考这样一个奇怪而有趣的问题:

在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:

如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。

当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。

输入格式:
第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。
第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。

输出格式:
输出一个整数,表示不同连号区间的数目。

示例:
用户输入:
4
3 2 4 1

程序应输出:
7

用户输入:
5
3 4 2 5 1

程序应输出:
9

解释:
第一个用例中,有7个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]
第二个用例中,有9个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]

分析 

时间复杂度:O(nlogn)

性质分析:一个区间为连号区间[l,r],等价于这个区间中,最大值mx-最小值mi=r-l。记vi=mx-mi+l,我们枚举区间的右端点r,对于每一个l(l>=1&&l<=r-1)维护在区间[l,r]的vi。其中[i,r]的值可以由[i,r-1]变换而来,当r是其中的最大值时,加上a[r]-a[r-1]的差值,当r是其中的最小值时,加上a[r-1]-a[r]。我们用单调栈st1来存储区间的最大值的元素下标,栈中两个相邻的元素w,w+1代表在st1[w]+1与st1[w+1]这个区间的内的i,有区间[i,r]最大值为a[st1[w+1]]。区间最小值的维护同上。当我们计算完每个区间的vi时,只要统计与r相等的vi数量即可,但是线段树并不支持区间修改和个数统计同时进行。注意到:vi>=r,也就是说r是所有vi的最小值而且这个最小值一定存在(对于从右端点为r的情况,至少存在一个[r,r]区间满足条件),我们使用线段树统计最小值的个数即可得出结果。

使用数据结构:两个单调栈st1,st2维护区间的最大值和最小值,一个维护区间最小值数量的线段树

AC代码:

import java.awt.image.ComponentSampleModel;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;

public class Main {
    final static int M=(int) 50+5;
    final static int N=(int) 5e4+5;
    final static int MOD=(int) 50+5;
    final static int BIG=(int)21e8+5;
    final static Main main=new Main();
    static int[] a=new int[N];
    static int[] st1=new int[N];
    static int[] st2=new int[N];

    class Data implements Comparable<Data>,Cloneable{
        public int val,num;

        @Override
        public int compareTo(Data o) {
            return (int) (val-o.val);
        }
        public Data add(Data o){
            num+=o.num;
            return this;
        }

        public Data(int val, int num) {
            this.val = val;
            this.num = num;
        }

        public Data() {
        }

        @Override
        protected Data clone(){
            try {
                super.clone();
            } catch (CloneNotSupportedException e) {
                throw new RuntimeException(e);
            }
            Data d=new Data(val,num);
            return d;
        }
    }
    class Node{
        int l,r;
        int lz;
        Data data;
    }
    static Node[] nd=new Node[4*N];

    static void push_back(int i){
        Data a,b;
        a=nd[2*i].data.clone();
        b=nd[2*i+1].data.clone();
        if(a.compareTo(b)<0){
            nd[i].data=a;
        } else if (a.compareTo(b) == 0) {
            nd[i].data=a.add(b);
        }else {
            nd[i].data=b;
        }
    }
    static void push_down(int i){
        Node n=nd[i];
        if(n.lz!=0){
            nd[2*i].lz+=n.lz;
            nd[2*i+1].lz+=n.lz;
            nd[2*i].data.val+=n.lz;
            nd[2*i+1].data.val+=n.lz;
            n.lz=0;
        }
    }
    static void make(int i,int l,int r){
        nd[i]=main.new Node();
        nd[i].l=l;
        nd[i].r=r;
        if(l==r){
            nd[i].data=main.new Data(l,1);
            return;
        }
        int mid=(l+r)/2;
        make(2*i,l,mid);
        make(2*i+1,mid+1,r);
        push_back(i);
    }

    static void update(int i,int l,int r,int val){
        Node n=nd[i];
        if(n.l>r||n.r<l) return;
        if(n.l>=l&&n.r<=r){
            n.data.val+=val;
            n.lz+=val;
            return;
        }
        push_down(i);
        if(l<=nd[2*i].r){
            update(2*i,l,r,val);
        }
        if(r>=nd[2*i+1].l){
            update(2*i+1,l,r,val);
        }
        push_back(i);
    }
    static Data query(int i,int l,int r){
        Node n=nd[i];

        if(n.l>=l&&n.r<=r){
           return n.data;
        }

        Data ans=main.new Data(BIG,0);;
        if(n.l>r||n.r<l){
            return ans;
        }
        push_down(i);
        Data a,b;
        a=main.new Data(BIG,0);
        b=main.new Data(BIG,0);
        if(l<=nd[2*i].r){
            a=query(2*i,l,r).clone();
        }
        if(r>=nd[2*i+1].l){
            b=query(2*i+1,l,r).clone();
        }
        if(a.compareTo(b)<0) ans=a;
        else if (a.compareTo(b) == 0) {
            ans=a.add(b);
        }else {
            ans=b;
        }
        push_back(i);
        return ans;
    }
    class Pair implements Comparable<Pair>{
        public int len;
        public int value;

        @Override
        public int compareTo(Pair o) {
            if(o.value!=value){
                return value-o.value;
            }else {
                return o.len - len;
            }
        }
    }
    public static void main(String[] args) throws IOException{

        Input sc=main.new Input();
        PrintWriter out =new PrintWriter(new OutputStreamWriter(System.out));
        long ans=0;
        int n;
        n= sc.nextInt();
        make(1,1,n);
        int top1,top2;
        top1=0;
        top2=0;
        for(int i=1;i<=n;i++){
            a[i]= sc.nextInt();
            while (top1!=0&&a[st1[top1]]<=a[i]){
                update(1,st1[top1-1]+1,st1[top1],a[i]-a[st1[top1]]);
                top1--;
            }
            st1[++top1]=i;
            while (top2!=0&&a[st2[top2]]>=a[i]){
                update(1,st2[top2-1]+1,st2[top2],a[st2[top2]]-a[i]);
                top2--;
            }
            st2[++top2]=i;
            Data d=query(1,1,i);
            ans+=d.num;
        }
        out.println(ans);
        out.close();
    }
    class Input {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public Input()  {
            try {
                if (System.getProperty("ONLINE_JUDGE")==null) {
                    reader = new BufferedReader(new FileReader("C:\\Users\\Limhuang\\IdeaProjects\\BlueBrige\\src\\main\\resources\\org\\example\\in.txt"));
                } else {
                    reader = new BufferedReader(new InputStreamReader(System.in));
                }
            }catch (Exception e){
                reader = new BufferedReader(new InputStreamReader(System.in));
            }

            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public String nextLine() {
            String str = null;
            try {
                str = reader.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public Double nextDouble() {
            return Double.parseDouble(next());
        }

        public BigInteger nextBigInteger() {
            return new BigInteger(next());
        }
    }
}

 

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值