bzoj2124 等差子序列
2016-06-05 19:54
218 查看
Description
给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列。
Input
输入的第一行包含一个整数T,表示组数。下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
Output
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。
从左到右扫描,用二进制01串记录每个数字是否出现过。对于每个数字,考虑它是否能作为等差中项。如果能,那么一定有一对x-d,x+d对应的01值不相等【也就是一个出现过,一个没有出现过】。这就意味着两个数一个在他之前,一个在他之后。我们也就找到了一组等差数列。比较的时候,我们只需要比较他左右能延伸的最远的01串即可。注意一个正序一个倒序。
因为是单点修改,区间询问,所以可以用线段树完成。每个结点维护正序和逆序的哈希值。
给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列。
Input
输入的第一行包含一个整数T,表示组数。下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
Output
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。
从左到右扫描,用二进制01串记录每个数字是否出现过。对于每个数字,考虑它是否能作为等差中项。如果能,那么一定有一对x-d,x+d对应的01值不相等【也就是一个出现过,一个没有出现过】。这就意味着两个数一个在他之前,一个在他之后。我们也就找到了一组等差数列。比较的时候,我们只需要比较他左右能延伸的最远的01串即可。注意一个正序一个倒序。
因为是单点修改,区间询问,所以可以用线段树完成。每个结点维护正序和逆序的哈希值。
#include<cstdio> #include<cstring> #define M(a) memset(a,0,sizeof(a)) int p=13331,s,r,a[10010],n; unsigned long long pow[10010]; struct node { int c[2],l,r; unsigned long long h[2]; }t[100100]; int max(int x,int y) { return x>y?x:y; } int min(int x,int y) { return x<y?x:y; } int abs(int x) { return x>0?x:-x; } void init() { int i; s=0; r=0; M(a); M(t); scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i]); } void up(int p) { node x=t[t[p].c[0]],y=t[t[p].c[1]]; t[p].h[0]=x.h[0]*pow[abs(y.l-y.r)+1]+y.h[0]; t[p].h[1]=y.h[1]*pow[abs(x.l-x.r)+1]+x.h[1]; } void build(int &p,int l,int r) { p=++s; t[p].l=l; t[p].r=r; if (l==r) return; build(t[p].c[0],l,(l+r)/2); build(t[p].c[1],(l+r)/2+1,r); } unsigned long long find(bool b,int p,int l,int r) { if (l==t[p].l&&r==t[p].r) return t[p].h[b]; int mid=(t[p].l+t[p].r)/2; if (r<=mid) return find(b,t[p].c[0],l,r); if (l>=mid+1) return find(b,t[p].c[1],l,r); unsigned long long u1=find(b,t[p].c[0],l,mid),u2=find(b,t[p].c[1],mid+1,r); if (!b) return u1*pow[r-mid]+u2; else return u2*pow[mid-l+1]+u1; } bool ok(int x) { int len=min(n-x,x-1); if (!len) return 0; unsigned long long u=find(0,r,x-len,x-1),v=find(1,r,x+1,x+len); return u!=v; } void mark(int p,int x) { if (t[p].l==t[p].r) { t[p].h[0]=t[p].h[1]=1; return; } int mid=(t[p].l+t[p].r)/2; if (x<=mid) mark(t[p].c[0],x); else mark(t[p].c[1],x); up(p); } int main() { int i,j,k,q,x,y,z,T; bool b; scanf("%d",&T); pow[0]=1; for (i=1;i<=10005;i++) pow[i]=pow[i-1]*p; while (T--) { init(); build(r,1,n); b=0; for (i=1;i<=n;i++) if (ok(a[i])) { printf("Y\n"); b=1; break; } else mark(r,a[i]); if (!b) printf("N\n"); } }
相关文章推荐
- Mootools 1.2教程 定时器和哈希简介
- C#获取哈希加密生成随机安全码的类实例
- C#计算字符串哈希值(MD5、SHA)的方法小结
- PowerShell中定义哈希散列(Hash)和调用例子
- PHP中创建和验证哈希的简单方法实探
- Perl 哈希的创建和引用介绍
- Perl 哈希Hash用法之入门教程
- perl哈希hash的常见用法介绍
- perl哈希的一个实例分析
- Go语言常见哈希函数的使用
- 线段树题集
- Data Structure - Week 16
- 线段树
- hashing (哈希)
- hdu1754
- HDU1394
- 敌兵布阵 (1)
- I Hate It (1)
- LCIS (2)
- A Simple Problem with Integers (2)