这题只要令 $len=3$看是否符合即可。因为是一个 $1$到 $n$的排列,考虑数列中项,那么对于一个数 $x$,令 $k=max(n-x, x-1)$,只要存在 $din(1,k)$,使 $x+d$和 $x-d$位于数 $x$在序列中的位置的异侧即可。进一步分析我们要做的就是从左向右扫一遍序列,每扫过一个数就将其在值域区间上打上标记,对于目前扫到的数 $x$,判断在值域区间上以它为中心的左右长度为 $k$的区域是否对称,如果对称代表在 $[1,n]$范围内所有以它为中项的能与它形成等差数列的一对值都在同侧,不满足,否则满足。判断区间相等问题不难想到hash,用线段树维护即可。
#include<cstdio> #include<cstring> #define min(a,b) (a)<(b) ? (a):(b) #define ull unsigned long long const int maxn = 1e5+50; const int p = 998244353; int T,n; int a[maxn]; ull kk[maxn],hash[2][maxn<<2]; bool vis; void pushup(int x,int len){ int tt = len>>1; hash[0][x] = (hash[0][x<<1]*kk[tt]+hash[0][x<<1|1]) % p; hash[1][x] = (hash[1][x<<1]+hash[1][x<<1|1]*kk[len-tt]) % p; } void update(int x,int l,int r,int val){ if(l == r){ hash[0][x] = hash[1][x] = 1; return ; } int mid = l+r>>1; if(val <= mid) update(x<<1,l,mid,val); else update(x<<1|1,mid+1,r,val); pushup(x,r-l+1); } ull query(int x,int l,int r,int ql,int qr,int sta){ if(ql > qr) return 0; if(ql <= l && qr >= r) return hash[sta][x]; int mid = l+r>>1; if(qr <= mid) return query(x<<1,l,mid,ql,qr,sta); else if(ql > mid) return query(x<<1|1,mid+1,r,ql,qr,sta); ull dx = kk[qr-mid], dy = 1; if(sta) dx = 1, dy = kk[mid-ql+1]; return (query(x<<1,l,mid,ql,mid,sta)*dx+query(x<<1|1,mid+1,r,mid+1,qr,sta)*dy) % p; } int main(){ scanf("%d",&T); kk[0] = 1; for(int i = 1; i < maxn; ++i) kk[i] = kk[i-1]*3%p; while(T--){ memset(hash,0,sizeof(hash)); scanf("%d",&n); vis = 0; for(int i = 1; i <= n; ++i) scanf("%d",&a[i]); for(int i = 1; i <= n; ++i){ int q = min(a[i]-1,n-a[i]); if(query(1,1,n,a[i]-q,a[i]-1,0) != query(1,1,n,a[i]+1,a[i]+q,1)){ vis = 1; break; } update(1,1,n,a[i]); } puts(vis ? "Y":"N"); } return 0; }