[BZOJ]2124 等差子序列 Hash&树状数组
2017-12-12 20:10
253 查看
2124: 等差子序列
Time Limit: 3 Sec Memory Limit: 259 MBSubmit: 1719 Solved: 648
[Submit][Status][Discuss]
Description
给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列。
Input
输入的第一行包含一个整数T,表示组数。下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
N<=10000,T<=7
Output
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。Sample Input
23
1 3 2
3
3 2 1
Sample Output
NY
HINT
Source
[Submit][Status][Discuss]
HOME Back
好神啊好神啊... 以前认为Hash啥的不会很难, 果然还是我太弱了, 感觉还远远不够啊... orz了题解.
我们考虑题目中所描述的三个数的中间的那个数, 与之构成等差子序列的数为p和q, 位置p < x < q. 如果是从左到右枚举的话, 那么枚举到x, 如果有这样的p和q, 那么就应该是p出现过, q还没出现(x < q). 那么我们又知道q - x = x - p. 那么也就是说枚举到x的话, 只要前面存在与x相差d的一个p, 且当前x + d还没有出现的话,就能说明位置上p < x < x + d(注意这是个排列
),q就是x+d, 就能满足条件, 可以输出"Y"了。
我们会发现由等差这个性质可以得到p 是和x+d在值域上关于x对称(x - p = x + d - x). 那么用0, 1在值域上表示出或者没出现过, 当前枚举到x, 值域上关于x只要有一个不对称就能满足条件(因为这就说明了一个出现过一个没出现过,值域位置对称保证了等差, 一个出现一个没出现保证了序列上的位置关系). 然而我们又能发现不能满足条件的情况就是没有一个不对称 -- 那不就是处处都对称?? 这不就是值域上以x为中心的回文串吗?
那我们只需要判断以x为中心的极长字符串是不是回文串就可以了(因为这中间肯定有某个位置不对称才会导致这个字符串不是回文串). 判断用manacher? 实际上分成两部分hash判相等就可以了, 修改和查询可以用树状数组完成, 由于是分成两部分正反判相等, 要用到两个hash值. 详见代码.
启示: 就是当题目中给的限制屈指可数的时候, 可以尝试着枚举来找相邻之间的关系, 从限制的多个角度来考虑求解(位置, 值域...), 过程中还能从命题和反命题两方面思考来进行简化.
之前都不明白树状数组的性质乱用, 果然这道题就不知道怎么提取区间hash值了. 问了Doggu才知道hh.(加了读优还是比Doggu慢6ms咩?
#include<bits/stdc++.h> using namespace std; const int maxn = 1e4 + 5; int T, n, a[maxn]; unsigned int pw[maxn]; struct Binary { int i; unsigned int c[maxn], tmp1, tmp2; inline void clear() { memset(c, 0, sizeof(c)); } inline void modify(const int &x) { for (i = x; i <= n; i += i & -i) c[i] += pw[i - x]; } inline unsigned int query(const int &p, const int &q) { tmp1 = tmp2 = 0; for (i = p - 1; i; i ^= i & -i) tmp1 += c[i] * pw[p - 1 - i]; for (i = q; i; i ^= i & -i) tmp2 += c[i] * pw[q - i]; return tmp2 - tmp1 * pw[q - p + 1]; } }bit1, bit2; int main() { scanf("%d", &T); register int i, x; for (pw[0] = 1, i = 1; i < maxn; ++ i) pw[i] = pw[i - 1] * 10007; while (T --) { scanf("%d", &n); for (i = 1; i <= n; ++ i) scanf("%d", &a[i]); for (i = 1; i < n; ++ i) { x = min(a[i] - 1, n - a[i]); if (x && bit1.query(a[i] - x, a[i] - 1) != bit2.query(n - a[i] - x + 1, n - a[i])) break; bit1.modify(a[i]), bit2.modify(n - a[i] + 1); } (i >= n) ? puts("N") : puts("Y"); if (T) bit1.clear(), bit2.clear(); } return 0; }
相关文章推荐
- BZOJ 2124: 等差子序列 [树状数组][hash]
- BZOJ 2124 等差子序列 (树状数组 hash)
- bzoj2124 等差子序列 (树状数组 维护hash值)
- bzoj 2124: 等差子序列 树状数组&hash
- BZOJ 2124等差子序列 线段树&&hash
- bzoj 4448: [Scoi2015]情报传递 dfs序列&树状数组
- 【bzoj2124】等差子序列 权值线段树维护hash
- bzoj 2124: 等差子序列 (线段树+hash)
- [bzoj2124]等差子序列_线段树_hash
- BZOJ 2124 等差子序列 线段树维护hash值
- bzoj2124 等差子序列(hash+线段树)
- [乱搞 树状数组] BZOJ 4548 小奇的糖果 && BZOJ 3658 Jabberwocky
- Bzoj2124 等差子序列
- bzoj 3529: [Sdoi2014]数表 莫比乌斯反演&树状数组
- 【bzoj5157】[Tjoi2014]上升子序列 树状数组
- [BZOJ 2124] 等差子序列 Hash+树状数组(附粗略证明)
- BZOJ2124 等差子序列(树状数组+哈希)
- [BZOJ 1461] 字符串的匹配 · KMP & 树状数组
- URAL - 1989 Subpalindromes hash & 树状数组 | 线段树
- 【序列莫队+树状数组】BZOJ3289-Mato的文件管理