http://codevs.cn/problem/1283/

题目描述 Description

给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len>=3),使得 Ap1,Ap2,Ap3,…ApLen 是一个等差序列。

 
输入描述 Input Description

输入的第一行包含一个整数 T,表示组数。

下接 T 组数据,每组第一行一个整数 N,每组第二行为一个 1 到 N 的排列, 数字两两之间用空格隔开。

 
输出描述 Output Description

对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一 行“N”。

 
样例输入 Sample Input

2

3

1 3 2

3

3 2 1

 
样例输出 Sample Output

N

Y

 
数据范围及提示 Data Size & Hint

对于5%的数据,N<=100,对于30%的数据,N<=1000,对于100%的数据,N<=10000,T<=7

线段树+hash

首先要注意的是这个排列是1到n的排列

然后当然是找3个数形成等差子序列

暴力:枚举中间的数,枚举左边的数,枚举右边的数,看是否满足 2*mid=l+r

O(n³)

继续想,因为保证排列是1到n

所以对于一个数x,若以x为mid能形成等差子序列,那么另外两个数一定在x两侧

即从左往右枚举,当枚举到mid时,能早就枚举到了l,不能枚举到r

可以用0,1表示这个数是否被枚举到

举个例子:

3 6 1 2 4 5

当枚举到第5个数4时,0 1序列为

1 1 1 1 0 1

4的左边分别是1和0,说明枚举到4时,3已经被枚举到了,5还没有被枚举

但这样仍然要枚举,没有减少时间复杂度

如何去掉枚举的过程?

继续想,发现我们要比较的是mid左右的两个对称区间

举个例子:

1 8 3 6 5 7 4 2

当枚举到3时,0 1序列为:

1 0 1 0 0 0 0 1

我们实际需要的是判断2和4的01序列是否相等,1和5的01序列是否相等

因为是对称的

可以转化为判断区间[1,2]和区间[5,4](注意这里是[5,4],不是[4,5])是否相等

线段树维护区间正序哈希值和倒序哈希值,即可log判断

总复杂度:O(nlogn)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10001
#define LL unsigned long long
using namespace std;
int T,n,x,len;
bool ok;
LL bit[N],hash[N*],anti_hash[N*],r1,r2;
struct TREE
{
public:
void up(int k,int l,int r)
{
hash[k]=hash[k<<]*bit[r-(l+r>>)]+hash[k<<|];
anti_hash[k]=anti_hash[k<<|]*bit[(l+r>>)-l+]+anti_hash[k<<];
}
void change(int k,int l,int r,int pos)
{
if(l==r)
{
anti_hash[k]=hash[k]=;
return;
}
int mid=l+r>>;
if(pos<=mid) change(k<<,l,mid,pos);
else change(k<<|,mid+,r,pos);
up(k,l,r);
}
LL query(int k,int l,int r,int opl,int opr,int w)
{
if(l>=opl&&r<=opr) return w== ? hash[k]:anti_hash[k];
int mid=l+r>>;
if(opr<=mid) return query(k<<,l,mid,opl,opr,w);
else if(opl>mid) return query(k<<|,mid+,r,opl,opr,w);
else if(w==) return query(k<<,l,mid,opl,mid,w)*bit[opr-mid]+query(k<<|,mid+,r,mid+,opr,w);
else return query(k<<|,mid+,r,mid+,opr,w)*bit[mid-opl+]+query(k<<,l,mid,opl,mid,w);
}
void solve(int i)
{
len=min(i-,n-i);
r1=query(,,n,i-len,i-,);
r2=query(,,n,i+,i+len,);
if(r1!=r2) ok=true;
}
}tree;
int main()
{
bit[]=; for(int i=;i<N;i++) bit[i]=bit[i-]*;
scanf("%d",&T);
while(T--)
{
memset(hash,,sizeof(hash));
memset(anti_hash,,sizeof(anti_hash));
scanf("%d",&n);
ok=false;
for(int i=;i<=n;i++)
{
scanf("%d",&x);
if(!ok)
{
tree.change(,,n,x);
if(x!=&&x!=n) tree.solve(x);
}
}
if(ok) puts("Y");
else puts("N");
}
}

最新文章

  1. 疯狂的JSONP
  2. sql 脚本编写之路 常用语句(一)
  3. Ambari——大数据平台的搭建利器
  4. [转]使用Stopwatch类实现高精度计时
  5. 每天一个linux命令(59):rcp命令
  6. 新浪微博SDK开发(2):上传图片的技术难点
  7. codevs 1080 线段树练习
  8. 解决Volley请求网络数据返回的数据乱码
  9. Oracle Exadata体系笔记
  10. P90、面试题11:数值的整数次方
  11. 再跟SQL谈一谈--基础篇
  12. Android call setting 源码分析 (上)
  13. Java语言中IO流的操作规律学习笔记
  14. IE和Chrome执行javascript对鼠标双击事件的不同响应
  15. solvepnp
  16. python-随机操作(random)
  17. js调用winform程序(带参数)
  18. MVC--初步理解(01)
  19. Prufer codes与Generalized Cayley&#39;s Formula
  20. Python_问题收录总结

热门文章

  1. SpringBoot集成Shiro并用MongoDB做Session存储
  2. [BZOJ2467] [中山市选2010] 生成树 (排列组合)
  3. iOS开发--XMPPFramework--用户登录(三)
  4. SDN 网络系统之 Mininet 与 API 详解
  5. 性能优化之reflow和repaint
  6. Unity3D 心跳检测
  7. Unity3D 动画状态简单控制核心代码
  8. Python函数学习——递归
  9. FineReport破解心得
  10. 最小生成数(并查集)Kruskal算法