算法很顯然:c++
1、在區間\([l,r]\)找到一個只出現一次的元素P(若是不存在,那麼序列\(boring\))算法
2、遞歸處理區間\([l,p-1]\)和區間\([p+1,r]\)。spa
其關鍵在於如何找到一個只出現一次的元素P。code
首先,咱們得知道如何判斷一個元素是否是隻出現一次。遞歸
咱們能夠用\(STL\)中的\(map\)記錄與當前元素值相同的上一個元素 or 下一個元素的位置,而後更新便可。it
由於\(map\)的全部操做都是\(O(log_n)\)的,因此預處理的時間複雜度爲\(O(nlog_n)\)。ast
因此,咱們就能夠用\(O(1)\)的時間判斷出一個元素是否是隻出現一次了。class
若從左到右掃描整個序列,那麼最壞狀況,這個元素在序列的最右邊,則\(Time(n)=Time(n-1)+O(n) \ge Time(n^2)=O(n^2)\)。map
根據二分法(分治)通常是儘可能分紅兩個數量儘可能接近的數列,咱們能夠考慮從兩邊往中間找。im
此時,最壞狀況爲這個元素在序列的正中間,則\(Time(n)=2\times Time(n/2)+O(n)\),解得\(Time(n)=O(nlog_n)\)。
因此算法的總時間複雜度爲\(O(nlog_n)\)。
#include <bits/stdc++.h> using namespace std; int s[200010]; int last[200010]; int nxt[200010]; map<int,int>be; map<int,int>wi; inline bool solve(int l,int r){ if(l>=r) return 1; int x=l,y=r; while(x<=y){ if(last[x]<l&&nxt[x]>r) return solve(l,x-1)&&solve(x+1,r); else if(last[y]<l&&nxt[y]>r) return solve(l,y-1)&&solve(y+1,r); x++,y--; } return 0; } int main(){ int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); be.clear(); wi.clear(); for(int i=1;i<=n;i++) { scanf("%d",&s[i]); if(!be.count(s[i]))last[i]=-1; else last[i]=be[s[i]]; be[s[i]]=i; } for(int i=n;i>0;i--) { if(!wi.count(s[i]))nxt[i]=n+1; else nxt[i]=wi[s[i]]; wi[s[i]]=i; } if(solve(1,n)) printf("non-boring"); else printf("boring"); } return 0; }