题解:P5679 [GZOI2017] 等差子序列
分块+随机化算法
看到大标题大家应该知道怎么做了。
经过分析可知,我们只需证明有这样一个三元组
三元组元素个数少,考虑随机化。
对于一个三元组
采用分块的经典处理方式,我们将长度为
我们预先处理好每个元素最后出现的位置
三元组中,
时间复杂度方面,分块的好处又体现出来,单次取样时间复杂度为
于是我们取得最优解第一的好成绩。
# include <bits/stdc++.h>
using namespace std;
struct block
{
int l;
int r;
};
struct block blo[500];
int arr[20005];
int lst[12][20005];
int rd(int n)
{
return rand() % n + 1;
}
bool solve(int n,int m,int T)
{
int x = rd(m),y = rd(m);
if (x > y)
{
swap(x,y);
}
int l1 = blo[x].l;
int r1 = blo[x].r;
int l2 = blo[y].l;
int r2 = blo[y].r;
for (int i=l1;i<=r1;i++)
{
for (int j=max(l2,i+1);j<=r2;j++)
{
int tar = arr[j]*2 - arr[i];
if (tar>=0 && tar<=20000 && lst[T][tar] > j)
{
return true;
}
}
}
return false;
}
int main (void)
{
srand(time(NULL));
int T;
scanf("%d",&T);
while (T--)
{
int n;
scanf ("%d",&n);
for (int i=1;i<=n;i++)
{
scanf ("%d",&arr[i]);
lst[T][arr[i]] = i;
}
int siz = sqrt(n);
int bln = 0;
for (int i=1;(i-1)*siz+1<=n;i++)
{
blo[i].l = (i-1)*siz+1;
blo[i].r = min(i*siz,n);
bln++;
}
for (int i=0;i<500;i++)
{
if (solve(n,bln,T))
{
goto OK;
}
}
printf ("NO\n");
continue;
OK:
printf ("YES\n");
}
return 0;
}