码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj2124】等差子序列 STL-bitset

时间:2017-10-13 17:09:42      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:names   put   哈希   因此   子序列   数据   全排列   zoj   bit   

题目描述

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

输入

输入的第一行包含一个整数T,表示组数。
下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
N<=10000,T<=7

输出

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

样例输入

2
3
1 3 2
3
3 2 1

样例输出

N
Y


题解

STL-bitset

首先选出的长度一定为3(长度多了没有意义,只取前3项即可)。

然后枚举中间位置的数,转化为是否存在$i+k=2j$,其中$i$在$j$之前出现,$k$在$j$之后出现。

考虑暴力怎么求:对于前面和后面各开一个桶,暴力枚举。

由于给出的是一个全排列,因此每个数只出现1次,相当于开的桶是bool类型的。我们可以使用bitset优化。至于如何判断是否存在两个数的和为定值,可以维护$20000-i$和$k$,如果存在$i+k=2j$,那么$(20000-i)=k+(20000-2j)$。所以维护左边的$20000-i$和右边的$k$,如果把右面左移$20000-2j$后与$20000-i$的与不为0则存在。

时间复杂度$O(\frac{Tn^2}{16})$,分母不是32是因为bitset的范围需要开到2W。

貌似正解是分段哈希。

#include <cstdio>
#include <bitset>
using namespace std;
int v[10010];
int main()
{
	int T;
	scanf("%d" , &T);
	while(T -- )
	{
		bitset<20010> b , c;
		int n , i;
		scanf("%d" , &n);
		for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]) , c[v[i]] = 1;
		for(i = 1 ; i <= n ; i ++ )
		{
			c[v[i]] = 0;
			if(((b >> (20000 - (v[i] << 1))) & c).any())
			{
				puts("Y");
				break;
			}
			b[20000 - v[i]] = 1;
		}
		if(i > n) puts("N");
	}
	return 0;
}

 

 

【bzoj2124】等差子序列 STL-bitset

标签:names   put   哈希   因此   子序列   数据   全排列   zoj   bit   

原文地址:http://www.cnblogs.com/GXZlegend/p/7661707.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!