1. 程式人生 > >[分治] UVa1608 Non-boring sequences 不無聊序列 (分治與中途相遇法的結合)

[分治] UVa1608 Non-boring sequences 不無聊序列 (分治與中途相遇法的結合)

題目

這裡寫圖片描述

思路

1.主要思路:如果有一個只出現一次的元素A[p],那麼所有包含此元素的所有連續子序列都滿足不無聊。那麼只需分治判斷A[0~p-1]和A[p+1~n]是否不無聊即可。
2.分治方向的選擇:(上界分析

  1. 從左往右找:最壞情況是唯一元素恰好在最右邊。T(n)=T(n1)+O(n)=O(n2)
  2. 從右往左找:最壞情況是唯一元素恰好在最左邊。T(n)=T(n1)+O(n)=O(n2)
  3. 從兩頭往中間找(中途相遇法):最壞情況是唯一元素恰好在最中間。T(n)=2T(n/2)+O(n)=O(nlogn)
    (此處其實有點類似快排的方法)

程式碼

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <map>
using namespace std;

const int maxn = 200000+10000;
int n, A[maxn], myprev[maxn], mynext[maxn];
map<int, int> cur;

void init(){
    cur.clear();
    for
(int i = 0; i<n; i++){ if (!cur.count(A[i])) cur[A[i]] = -1; myprev[i] = cur[A[i]]; cur[A[i]] = i; } cur.clear(); for (int i = n-1; i>=0; i--){ if (!cur.count(A[i])){ cur[A[i]] = -1; } mynext[i] = cur[A[i]]; cur[A[i]] = i; } } bool
solve(int L, int R){ //printf("%d %d\n",L,R); if (L == R-1 || L>=R) return true; int i = L, j = R-1; //[i.j] while(i<=j){ if (!(myprev[i] >= L && myprev[i] < R) && !(mynext[i] >= L && mynext[i] < R) && i<=j) return solve(L,i) && solve(i+1,R); i++; if (!(myprev[j] >= L && myprev[j] < R) && !(mynext[j] >= L && mynext[j] < R) && i<=j) return solve(L,j) && solve(j+1,R); j--; } return false; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); // scanf的輸入效率??? for(int i = 0; i<n; i++) scanf("%d",&A[i]); init(); if (solve(0,n)) printf("non-boring\n"); else printf("boring\n"); } return 0; }