Uva-1608 Non-boring sequences(高效率演算法)

RJ28發表於2017-04-08

題意:如果一個序列的任意連續子序列中至少有一個只出現一次的元素,則稱這個序列是不無聊的.輸入一個n(n <= 200000)個元素的序列A,判斷它是不是無聊的.


分析:對一段序列[l,r]而言,我們先找到這整個序列中只出現了一次的元素,如果沒有那麼就可以直接返回false,假如我們得到了這個元素p,那麼接下來只需要遞迴的去檢查區間[l,p-1]和

[p+1,r]就行了,我們事先預處理出來每個元素前後最近相同元素的位置就可以o(1)的判斷這個數字是不是在某個子序列中只出現了一次,這樣我們可以掃一遍[l,r]來得到p.

設T(n)為規模為n時所需的時間,那麼T(n) = max(T(p-1) + T(n-p) + O(n)),最壞情況下T(n) = O(n^2).但是如果我們從兩邊開始同步找p,複雜度就變成了T(n) = max(T(p-1)+T(n-p)+min(p,n-p)),最壞情況下每次p都在[l,r]中點,此時T(n) = 2*T(n/2) + O(n) = O(n*log(n)).


#include <bits/stdc++.h>
#define N 200005
using namespace std;
int T,n,a[N],pre[N],suc[N];
unordered_map<int,int> f;
bool jud(int l,int r)
{
    if(l >= r) return true;
    int flag = 0;
    int x = l,y = r;
    while(x <= y)
    {
        if(pre[x] < l && (!suc[x] || suc[x] > r))
        {
            flag = x;
            break;
        }
        if(pre[y] < l && (!suc[y] || suc[y] > r))
        {
            flag = y;
            break;
        }
        x++,y--;
    }
    if(!flag) return false;
    return jud(l,flag-1)&&jud(flag+1,r);
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        f.clear();
        scanf("%d",&n);
        for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
        for(int i = 1;i <= n;i++)
        {
            pre[i] = f[a[i]];
            f[a[i]] = i;
        }
        f.clear();
        for(int i = n;i;i--)
        {
           suc[i] = f[a[i]];
           f[a[i]] = i;
        }
        cout<<(jud(1,n) ? "non-boring" : "boring")<<endl;
    }
}


相關文章