蓝桥杯 - 连号区间数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯 - 连号区间数相关的知识,希望对你有一定的参考价值。

历届试题 连号区间数  
时间限制:1.0s   内存限制:256.0MB
      
锦囊1
并查集。
锦囊2
从左到右扫描数组,将所有扫描到的数放到并查集中,将相邻的数在集合中合并。对于每个合并的集合记录下递增可连的次数和递减可连的次数以及数字出现的最早和最晚时刻。当新扫描的数过来时根据以上几个值来合并区间并维护。
问题描述

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

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

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

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

输入格式

第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。

第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。

输出格式

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

样例输入1
4
3 2 4 1
样例输出1
7
样例输入2
5
3 4 2 5 1
样例输出2
9
 
思路
连续的数列有什么特征呢,比如2,3,4,5,6。
开始是2,结尾是6,长度是5,即A[j]-A[i]+1=length。
区间[L,R]如果可以排成连续数列 ,那么[L,R]上的最大值和最小值正好是连续数列的两个端点。
从而满足上面关于长度的关系,即R-L+1=MAX-MIN+1。(区间长度等于元素相减的差)
于是将问题转变为枚举区间,查询区间最大值最小值。
 
实现
直接想到RMQ实现。
稍微玩点花样。
 
代码
 1 // 两遍RMQ写法
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 const int N = 50000 + 10;
 5 int n, a[N], ma[N], mi[N], d1[N][16], d2[N][16];
 6 
 7 void RMQ_INIT1(){
 8     for(int i = 0; i < n; i++) d1[i][0] = a[i];
 9     for(int j = 1; (1<<j) <= n; j++)
10         for(int i = 0; i + (1<<j) -1 < n; i++)
11             d1[i][j] = min(d1[i][j-1], d1[i+(1<<(j-1))][j-1]);
12 }
13 
14 void RMQ_INIT2(){
15     for(int i = 0; i < n; i++) d2[i][0] = a[i];
16     for(int j = 1; (1<<j) <= n; j++)
17         for(int i = 0; i + (1<<j) -1 < n; i++)
18             d2[i][j] = max(d2[i][j-1], d2[i+(1<<(j-1))][j-1]);
19 }
20 
21 int query1(int L, int R){
22     int k = 0;
23     while((1<<(k+1)) <= R-L+1) k++;
24     return min(d1[L][k], d1[R-(1<<k)+1][k]);
25 }
26 
27 int query2(int L, int R){
28     int k = 0;
29     while((1<<(k+1)) <= R-L+1) k++;
30     return max(d2[L][k], d2[R-(1<<k)+1][k]);
31 }
32 
33 int main(){
34     scanf("%d", &n);
35     for(int i = 0; i < n; i++) scanf("%d", a+i);
36 
37     RMQ_INIT1();
38     RMQ_INIT2();
39     int ans = 0;
40     for(int i = 0; i < n-1; i++){
41         for(int j = i+1; j < n; j++){
42             int mini = query1(i, j), maxi = query2(i, j);
43             if(j - i == maxi - mini) ans++;
44             // printf("%d %d , %d %d\n", i, j, mini, maxi);
45         }
46     }
47     printf("%d", ans+n);
48     return 0;
49 }

 

 1 // RMQ的非模版结构体写法,传入STL的max和min法
 2 // 注意用到了typedef简化了max和min的定义
 3 // template< class T > 
 4 // const T& max( const T& a, const T& b );
 5 #include<bits/stdc++.h>
 6 using namespace std;
 7 const int N = 50000 + 10;
 8 int n, a[N];
 9 
10 struct RMQ{
11     typedef const int& (&type)(const int&, const int&);
12     type func;
13     int n, **d;
14 
15     RMQ(type f, int size): func(f), n(size){
16         d = new int*[n];
17         for(int i = 0; i < n; i++) d[i] = new int[(int)(log(n)/log(2))+1];
18         RMQ_INIT();
19     }
20 
21     ~RMQ(){
22         delete[] d;
23     }
24 
25     void RMQ_INIT(){
26         for(int i = 0; i < n; i++) d[i][0] = a[i];
27         for(int j = 1; (1<<j) <= n; j++)
28             for(int i = 0; i + (1<<j) - 1 < n; i++)
29                 d[i][j] = func(d[i][j-1], d[i+(1<<(j-1))][j-1]);
30     }
31 
32     int query(int L, int R){
33         int k = 0;
34         while((1<<(k+1)) <= R-L+1) k++;
35         return func(d[L][k], d[R-(1<<k)+1][k]);
36     }
37 };
38 
39 int main(){
40     scanf("%d", &n);
41     for(int i = 0; i < n; i++) scanf("%d", a+i);
42     RMQ MAX(max,n), MIN(min,n);
43     int ans = 0;
44     for(int i = 0; i < n-1; i++){
45         for(int j = i+1; j < n; j++){
46             int mini = MIN.query(i, j), maxi = MAX.query(i, j);
47             if(j - i == maxi - mini) ans++;
48             // printf("%d %d , %d %d\n", i, j, mini, maxi);
49         }
50     }
51     printf("%d", ans+n);
52     return 0;
53 }

 

 1 // RMQ的模版结构体写法,传入STL的max和min法
 2 // 数组a也应该单独用模版写,不过不能放在全局部分
 3 #include<bits/stdc++.h>
 4 using namespace std;
 5 const int N = 50000 + 10;
 6 int n, a[N];
 7 template<class T>
 8 struct RMQ{
 9     typedef const T& (&type)(const T&, const T&);
10     type func;
11     int n; T **d;
12 
13     RMQ(type f, int size): func(f), n(size){
14         d = new T*[n];
15         for(int i = 0; i < n; i++) d[i] = new T[(int)(log(n)/log(2))+1];
16         RMQ_INIT();
17     }
18 
19     ~RMQ(){
20         delete[] d;
21     }
22 
23     void RMQ_INIT(){
24         for(int i = 0; i < n; i++) d[i][0] = a[i];
25         for(int j = 1; (1<<j) <= n; j++)
26             for(int i = 0; i + (1<<j) - 1 < n; i++)
27                 d[i][j] = func(d[i][j-1], d[i+(1<<(j-1))][j-1]);
28     }
29 
30     int query(int L, int R){
31         int k = 0;
32         while((1<<(k+1)) <= R-L+1) k++;
33         return func(d[L][k], d[R-(1<<k)+1][k]);
34     }
35 };
36 
37 int main(){
38     scanf("%d", &n);
39     for(int i = 0; i < n; i++) scanf("%d", a+i);
40     RMQ<int> MAX(max,n), MIN(min,n);
41     int ans = 0;
42     for(int i = 0; i < n-1; i++){
43         for(int j = i+1; j < n; j++){
44             int mini = MIN.query(i, j), maxi = MAX.query(i, j);
45             if(j - i == maxi - mini) ans++;
46             // printf("%d %d , %d %d\n", i, j, mini, maxi);
47         }
48     }
49     printf("%d", ans+n);
50     return 0;
51 }

 

以上是关于蓝桥杯 - 连号区间数的主要内容,如果未能解决你的问题,请参考以下文章

蓝桥杯 - 连号区间数

蓝桥杯历届试题 连号区间数

蓝桥杯 历届试题 连号区间数 解题报告

第四届蓝桥杯真题 连号区间

树状数组求逆序数 。,。 蓝桥杯 小朋友排队

连号区间数