2124: 等差子序列 - BZOJ

Description

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

Input

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

Output

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

Sample Input

2

3

1 3 2

3

3 2 1

Sample Output

N

Y

HINT

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

首先觉得题目不错(2013年我竟然在wikioi过了,代码还很短,然后把代码翻出来,发现是暴力n方加优化代码。。。。。。汗,我当时怎么想的)

今天看到题目觉得没什么想法,于是就翻了题解http://seter.is-programmer.com/posts/31902.html

就是维护每一个数字a[i]之前出现a[i]-1,a[i]-2,a[i]-3...的出现情况和a[i]+1,a[i]+2,a[i]+3...的出现情况(用二进制)

如果这两个二进制数的第k位不同,那么就是a[i]-k在a[i]前出现了,a[i]+k在a[i]之后出现或者a[i]+k在a[i]前出现了,a[i]-k在a[i]之后出现,所以我们只要判断两个二进制不同,就可以用hash值来判断了(不放心的话可以做两个hash),用线段树维护hash值就行了

  1 const
2 maxn=10010;
3 h=1000000007;
4 type
5 node=record
6 l,r,lc,rc:longint;
7 h1,h2:int64;
8 end;
9 var
10 f:array[0..maxn*2]of node;
11 a:array[0..maxn]of longint;
12 p:array[0..maxn]of int64;
13 t,n,tot:longint;
14
15 function min(x,y:longint):longint;
16 begin
17 if x<y then exit(x);
18 exit(y);
19 end;
20
21 function max(x,y:longint):longint;
22 begin
23 if x>y then exit(x);
24 exit(y);
25 end;
26
27 procedure add(x,now:longint);
28 var
29 mid:longint;
30 begin
31 if f[now].l=f[now].r then
32 begin
33 f[now].h1:=1;
34 f[now].h2:=1;
35 exit;
36 end;
37 mid:=(f[now].l+f[now].r)>>1;
38 if x>mid then add(x,f[now].rc)
39 else add(x,f[now].lc);
40 f[now].h1:=(f[f[now].lc].h1*p[f[now].r-mid]+f[f[now].rc].h1)mod h;
41 f[now].h2:=(f[f[now].rc].h2*p[mid-f[now].l+1]+f[f[now].lc].h2)mod h;
42 end;
43
44 procedure build(l,r:longint);
45 var
46 now,mid:longint;
47 begin
48 inc(tot);
49 now:=tot;
50 f[now].l:=l;
51 f[now].r:=r;
52 f[now].h1:=0;
53 f[now].h2:=0;
54 f[now].lc:=0;
55 f[now].rc:=0;
56 if l=r then exit;
57 mid:=(l+r)>>1;
58 f[now].lc:=tot+1;
59 build(l,mid);
60 f[now].rc:=tot+1;
61 build(mid+1,r);
62 end;
63
64 function hash1(l,r,now:longint):int64;
65 var
66 mid:longint;
67 begin
68 if (l<=f[now].l) and (r>=f[now].r) then exit(f[now].h1);
69 mid:=(f[now].l+f[now].r)>>1;
70 if l>mid then exit(hash1(l,r,f[now].rc));
71 if r<=mid then exit(hash1(l,r,f[now].lc));
72 exit((hash1(l,r,f[now].lc)*p[min(r,f[now].r)-mid]+hash1(l,r,f[now].rc))mod h);
73 end;
74
75 function hash2(l,r,now:longint):int64;
76 var
77 mid:longint;
78 begin
79 if (l<=f[now].l) and (r>=f[now].r) then exit(f[now].h2);
80 mid:=(f[now].l+f[now].r)>>1;
81 if l>mid then exit(hash2(l,r,f[now].rc));
82 if r<=mid then exit(hash2(l,r,f[now].lc));
83 exit((hash2(l,r,f[now].rc)*p[mid-max(l,f[now].l)+1]+hash2(l,r,f[now].lc))mod h);
84 end;
85
86 procedure main;
87 var
88 i:longint;
89 begin
90 read(n);
91 for i:=1 to n do
92 read(a[i]);
93 tot:=0;
94 build(1,n);
95 for i:=2 to n-1 do
96 begin
97 add(a[i-1],1);
98 if hash1(a[i]-min(a[i]-1,n-a[i]),a[i],1)=hash2(a[i],a[i]+min(a[i]-1,n-a[i]),1) then continue;
99 writeln(‘Y‘);
100 exit;
101 end;
102 writeln(‘N‘);
103 end;
104
105 begin
106 p[0]:=1;
107 for t:=1 to maxn do
108 p[t]:=p[t-1]*2 mod h;
109 read(t);
110 while t>0 do
111 begin
112 dec(t);
113 main;
114 end;
115 end.

View
Code

2124: 等差子序列 - BZOJ,布布扣,bubuko.com

时间: 2024-10-05 04:40:48

2124: 等差子序列 - BZOJ的相关文章

BZOJ 2124: 等差子序列 线段树维护hash

2124: 等差子序列 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”. Sample Input 2 3 1 3 2 3 3 2 1 Sample Output N Y HI

BZOJ 2124: 等差子序列

Sol 线段树+Hash. 首先暴力 等差子序列至少3项就可以了,就枚举中项,枚举公差就可以了,只需要一个数在中项前出现,另一个数在中项前没出现过就可以了.复杂度 \(O(n^2)\) 然后我想了一个虽然复杂度没变(因为我不会设计这个数据结构...) 但是好像有点用的算法,就是枚举中项,考虑从一个中项转移到另一个中项,那就是 \(\pm \Delta\) 就可以了...如果能够用数据结构维护这个操作,那就灰常好了.变换中项也就是变换折叠的位置吧. 标算呢...就是用线段树维护Hash,一个数字出

BZOJ 2124等差子序列 线段树&amp;&amp;hash

[题目描述 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 Desc

bzoj 2124 等差子序列 树状数组维护hash+回文串

等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 1919  Solved: 713[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数. 下接T组数据,

[bzoj2124]等差子序列(hash+树状数组)

我又来更博啦 2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 941  Solved: 348[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. O

bzoj2124 等差子序列(hash+线段树)

2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 719  Solved: 261[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对

BZOJ [P2124] 等差子序列

线段树维护哈希值 要求出现长度大于三的等差子序列,我们只要找到长度等于三的就可以了 初看本题没有思路,只能暴力枚举,O(n^4) 后来发现,这个序列是n的一个排列,那么每个数字都只会出现一次 我们可以维护一个 \(01\) 序列 B ,表示某个数字是否出现过, 然后我们从左往右枚举等差中项x并将该项在B中置为1,存在等差数列当且仅当, B序列以x为中心的极大子区间不是回文子区间 我们该如何高效的判断回文子区间呢,首先维护B的正反两个序列 然后有两种做法 1.线段树维护 \(01\) 序列的哈希值

Bzoj2124 等差子序列

Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 911  Solved: 337 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”.

Codevs 1283 等差子序列

1283 等差子序列 2010年 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Description 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len>=3),使得 Ap1,Ap2,Ap3,…ApLen 是一个等差序列. 输入描述 Input Description 输入的第一行包含一个整数 T,表示组数. 下接 T 组数据,每组第