藍橋杯-連號區間數

小程xy發表於2024-05-11

小明這些天一直在思考這樣一個奇怪而有趣的問題:

在 1∼N 的某個排列中有多少個連號區間呢?

這裡所說的連號區間的定義是:

如果區間 [L,R] 裡的所有元素(即此排列的第 L 個到第 R 個元素)遞增排序後能得到一個長度為 R−L+1 的“連續”數列,則稱這個區間連號區間。

當 N 很小的時候,小明可以很快地算出答案,但是當 N 變大的時候,問題就不是那麼簡單了,現在小明需要你的幫助。

輸入格式

第一行是一個正整數 N,表示排列的規模。

第二行是 N 個不同的數字 Pi,表示這 N 個數字的某一排列。

輸出格式

輸出一個整數,表示不同連號區間的數目。

資料範圍

1≤N≤10000,
1≤Pi≤N

輸入樣例1:

4
3 2 4 1

輸出樣例1:

7

輸入樣例2:

5
3 4 2 5 1

輸出樣例2:

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]

題解:

先解釋下題意, 也就是說給你一個序列, 序列中包含1 ~ n的數, 而且不重不漏, 現在問你任意一子區間排序後是連續遞增區間的有幾個 (之所以說不重不漏是因為題中說的是1-n的排列)
比如樣例1: 3 2 4 1
3, 4, 2, 1它們單獨是一個區間 ->4個
3 2 ->1個
3 2 4 ->1個
3 2 4 1 ->1個
4 + 1 + 1 + 1 = 7

正常純暴力的寫法 時間複雜度O(n^3)
只能過一半的資料, 其他的超時

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10, MAX = 1e8;

int main()
{
    int a[N], b[N];
    int n; cin >> n;
    for (int i = 0; i < n; i ++) cin >> a[i];
    
    int res = 0;
    for (int i = 0; i < n; i ++)
        for (int j = i; j < n; j ++)
        {
            // 判斷是否是滿足題意的子區間
            bool f = true;
            memcpy(b, a + i, sizeof(int) * (j - i + 1));
            sort(b, b + (j - i + 1)); 

            for (int k = 1; k < j - i + 1; k ++) 
                if (b[k - 1] != b[k] - 1) 
                {
                    f = false;
                    break;
                }
            if (f) res ++;
        }
    
    cout << res << endl;
    return 0;
}

我們可以最佳化一下 "判斷子序列是否是滿足題意得子區間這個步驟"

  • 由於整個序列是排列(不重不漏), 所以當一個子區間中的 最大值 - 最小值 等於 區間個數減一 的話就是滿足題意的子區間
  • 即 max - min = r - l ---> (max是子區間的最大值, min是子區間的最小值, r, l分別是子區間左右邊界元素的下標)

ac程式碼👇 時間複雜度(O(n^2))

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10, MAX = 1e8;
int a[N];
int main()
{
    int n; cin >> n;
    for (int i = 0; i < n; i ++) cin >> a[i];
    
    int res = 0;
    for (int i = 0; i < n; i ++)
    {
        int mn = MAX, mx = -MAX;
        for (int j = i; j < n; j ++)
        {
            // 最佳化後的判斷滿足題意的子區間
            mn = min(mn, a[j]);
            mx = max(mx, a[j]);
            if (mx - mn == j - i) res ++;
        }
    }
    cout << res << endl;
    return 0;
}

覺得寫的不錯的話, 點個贊吧~

相關文章