51nod 1272 最大距離 思維題

題目:

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1272

題意:

給出一個長度爲N的整數數組A,對於每一個數組元素,如果他後面存在大於等於該元素的數,則這兩個數可以組成一對。每個元素和自己也可以組成一對。例如:{5, 3, 6, 3, 4, 2},可以組成11對,如下(數字爲下標):
(0,0), (0, 2), (1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (3, 3), (3, 4), (4, 4), (5, 5)。其中(1, 4)是距離最大的一對,距離爲3。
Input
第1行:1個數N,表示數組的長度(2 <= N <= 50000)。
第2 - N + 1行:每行1個數,對應數組元素Ai(1 <= Ai <= 10^9)。
Output
輸出最大距離。

思路:

有三種思路。
第一種:排序。先按值排序,值相等就按位置排序,然後依次遍歷

#include <bits/stdc++.h>
using namespace std;

const int N = 50000 + 10, INF = 0x3f3f3f3f;

struct node
{
    int x, id;
}a[N];
bool cmp(node a, node b)
{
    if(a.x != b.x) return a.x < b.x;
    else return a.id < b.id;
}
int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i].x), a[i].id = i;
    sort(a + 1, a + 1 + n, cmp);
    int ans = 0, idx = 0;//idx保存目前遇到的最左端的位置
    for(int i = 1; i <= n; i++)
    {
        if(i == 1 || idx > a[i].id) idx = a[i].id;//當idx大於當前位置的時候,更新最左端位置
        else ans = max(ans, a[i].id - idx);//否則更新答案
    }
    printf("%d\n", ans);
    return 0;
}

第二種:二分枚舉區間,確定大於等於當前值且最右的位置,這裏用了RMQ,用線段樹也可以

#include <bits/stdc++.h>
using namespace std;

const int N = 50000 + 10, INF = 0x3f3f3f3f;

int dp[20][N], a[N];
void ST(int n)
{
    for(int i = 1; i <= n; i++)
        dp[0][i] = a[i];
    for(int i = 1; (1<<i) <= n; i++)
        for(int j = 1; j <= n - (1<<i) + 1; j++)
            dp[i][j] = max(dp[i-1][j], dp[i-1][j+(1<<(i-1))]);
}
int RMQ(int l, int r)
{
    int k = log(r - l + 1) / log(2.0);
    return max(dp[k][l], dp[k][r-(1<<k)+1]);
}
int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    ST(n);
    int ans = 0;
    for(int i = 1; i <= n; i++)
    {
        int l = i+1, r = n, t = 0;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(RMQ(mid, r) >= a[i]) t = mid, l = mid+1;
            else r = mid-1;
        }
        ans = max(ans, t - i);
    }
    printf("%d\n", ans);

    return 0;
}

第三種:維護一個單調棧,從棧底到棧頂遞減。然後對於每一個值,二分找到小於等於它且最左端的值,更新答案。關於棧要單調遞減,這是因爲如果大於等於棧頂,可以發現對答案並沒有什麼貢獻

#include <bits/stdc++.h>
using namespace std;

const int N = 50000 + 10, INF = 0x3f3f3f3f;

int a[N], stk[N];

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    int ans = 0, top = 0;
    for(int i = 1; i <= n; i++)
    {
        if(top == 0 || a[stk[top-1]] > a[i]) stk[top++] = i;
        int l = 0, r = top-1, t = i;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(a[stk[mid]] <= a[i]) t = mid, r = mid - 1;
            else l = mid + 1;
        }
        ans = max(ans, i - stk[t]);
    }
    printf("%d\n", ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章