對於一個數字序列。a1~n判斷是否任意一個連續子序列都存在一個數字只出現了一次 ai<=10^9, n<=20^5
非常扯犢子的題目.
這題看了思路其實很簡單。。。但是爲什麼要雙向同時查找呢。據說這就相當於。啓發式合併的逆過程所以就nlogn了。。我不會告訴你其實每次隨機一邊開始掃也是一樣的複雜度。。。
#include <cstdio>
#include <cmath>
#include <ctime>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#include<map>
#define forup(i,a,b) for(int i=(a);i<=(b);i++)
#define fordown(i,a,b) for(int i=(a);i>=(b);i--)
#define maxn 2000005
using namespace std;
template<class T> inline
void read(T& num){ num = 0; bool f = true;char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = false;ch = getchar();} while(ch >= '0' && ch <= '9') {num = num * 10 + ch - '0';ch = getchar();} num = f ? num: -num; }
int T,n;
int a[maxn];
int nxt[maxn],pre[maxn];
map<int,int> num;
bool solve(int L,int R)
{ if(L>=R) return true;
int l=L,r=R;
while(((nxt[l]<=R&&nxt[l]!=0)||(pre[l]>=L&&pre[l]!=0))&&((nxt[r]<=R&&nxt[r]!=0)||(pre[r]>=L&&pre[r]!=0)))
{l++;r--;
if(l>r) return false;
}
if((nxt[l]>R||nxt[l]==0)&&(pre[l]<L||pre[l]==0)) return solve(L,l-1)&&solve(l+1,R);
else return solve(L,r-1)&&solve(r+1,R);
}
int main()
{cin>>T;
while(T--)
{read(n);//forup(i,0,n+1) { pre[i]=0,nxt[i]=0;}
num.clear();
forup(i,1,n) {read(a[i]);pre[i]=num[a[i]];num[a[i]]=i; }
num.clear();
fordown(i,n,1) {nxt[i]=num[a[i]];num[a[i]]=i;}
if(solve(1,n)) printf("yes\n");else printf("no\n");
}
return 0;
}