藍橋杯 - 連號區間數
阿新 • • 發佈:2017-05-13
clu rmq template 最大 時間 最大值和最小值 所有 mes button 歷屆試題 連號區間數
時間限制:1.0s 內存限制:256.0MB
錦囊1
並查集。
錦囊2
從左到右掃描數組,將所有掃描到的數放到並查集中,將相鄰的數在集合中合並。對於每個合並的集合記錄下遞增可連的次數和遞減可連的次數以及數字出現的最早和最晚時刻。當新掃描的數過來時根據以上幾個值來合並區間並維護。
問題描述
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~N的某個全排列中有多少個連號區間呢?這裏所說的連號區間的定義是:
如果區間[L, R] 裏的所有元素(即此排列的第L個到第R個元素)遞增排序後能得到一個長度為R-L+1的“連續”數列,則稱這個區間連號區間。
當N很小的時候,小明可以很快地算出答案,但是當N變大的時候,問題就不是那麽簡單了,現在小明需要你的幫助。
輸入格式第一行是一個正整數N (1 <= N <= 50000), 表示全排列的規模。
第二行是N個不同的數字Pi(1 <= Pi <= N), 表示這N個數字的某一全排列。
輸出格式輸出一個整數,表示不同連號區間的數目。
樣例輸入1 43 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]如果可以排成連續數列 ,那麽[
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(){ 8for(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 }
藍橋杯 - 連號區間數