【bzoj2124】等差子序列 权值线段树维护hash
2016-04-06 19:29
651 查看
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<=7Source
神脑洞只需要看是否能构成长度为三的等差数列即可。枚举中项x,对于一个数x,从左到右添加到集合中,若x-d和x+d都已经出现了,则x必定不合法。
那么出现过记为1,没出现记为0,则得到了一个{1…x-1}和{x+1…n}的01串。若有一个不相同则表明存在一个x-d和x+d只出现了一次,则另一个肯定在后面出现,这便构成一个等差数列。
所以每次把x丢进权值线段树里,查询前面和后面的hash值就行了。记住朝左和朝右的长度要相同……因为这个WA了一次
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const int SZ = 10010; const int mod = 1000000007; struct segment{ int l,r; int h[2]; }tree[SZ << 2]; int mi[SZ]; void update(int p) { int lch = p << 1,rch = p << 1 | 1; int llen = tree[lch].r - tree[lch].l + 1; int rlen = tree[rch].r - tree[rch].l + 1; tree[p].h[0] = (tree[lch].h[0] + (LL)tree[rch].h[0] * mi[llen] % mod) % mod; tree[p].h[1] = (tree[rch].h[1] + (LL)tree[lch].h[1] * mi[rlen] % mod) % mod; } void build(int p,int l,int r) { tree[p].l = l; tree[p].r = r; if(l == r) { tree[p].h[1] = tree[p].h[0] = 0; return ; } int mid = l + r >> 1; build(p << 1,l,mid); build(p << 1 | 1,mid + 1,r); update(p); } void insert(int p,int x) { if(tree[p].l == tree[p].r) { tree[p].h[1] = tree[p].h[0] = 1; return ; } int mid = tree[p].l + tree[p].r >> 1; if(x <= mid) insert(p << 1,x); else insert(p << 1 | 1,x); update(p); } int geth(int p,int l,int r,int d) { if(l == tree[p].l && tree[p].r == r) return tree[p].h[d]; int mid = tree[p].l + tree[p].r >> 1; if(r <= mid) return geth(p << 1,l,r,d); else if(l > mid) return geth(p << 1 | 1,l,r,d); else { int a = geth(p << 1,l,mid,d),b = geth(p << 1 | 1,mid + 1,r,d); int llen = mid - l + 1; int rlen = r - mid; if(d == 0) return (a + (LL)b * mi[llen] % mod) % mod; else return (b + (LL)a * mi[rlen] % mod) % mod; } } void init() { memset(tree,0,sizeof(tree)); } void scanf(int &x) { x = 0; char a = getchar(); bool flag = 0; while(a < '0' || a > '9') { if(a == '-') flag = 1; a = getchar(); } while(a >= '0' && a <= '9') { x = x * 10 + a - '0'; a = getchar(); } if(flag) x = -x; } int main() { int T; scanf(T); mi[0] = 1; for(int i = 1;i <= 10000;i ++) mi[i] = (LL)mi[i - 1] * 13331 % mod; while(T --) { init(); int n; scanf(n); build(1,1,n); bool flag = 0; for(int i = 1;i <= n;i ++) { int x; scanf(x); insert(1,x); int len = min(x - 1,n - x); if(x != 1 && x != n && !flag && geth(1,x - len,x - 1,0) != geth(1,x + 1,x + len,1)) flag = 1; } if(!flag) puts("N"); else puts("Y"); } return 0; }
相关文章推荐
- linux文件系统
- Linux中vim中出现H不能正常编辑的问题
- arm-linux内存管理学习笔记(2)-内核临时页表的建立
- 网站架构演变
- adb shell error: unknown host service
- 1.8.1 Nginx+Tomcat实现单IP、多域名、多站点的访问
- 使用OpenCV实现分水岭算法
- 【Linux】java jdk安装路径查看和设置环境变量
- Linux的进程/线程间通信方式总结 02
- Linux常见命令小结1
- 通过PowerShell查看Android端log信息
- 常用网站
- Apache实现weblogic集群配置(转)
- Nginx配置一个自签名的SSL证书
- Linux 中的零拷贝技术
- Linux文件访问
- popen管道
- S5PV210 Linux内核按键中断实验
- nginx make报错
- 五种利用strace查故障的简单方法