bzoj2124 等差子序列(hash+线段树)
2015-11-21 19:41
411 查看
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
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。Sample Input
23
1 3 2
3
3 2 1
Sample Output
NY
HINT
对于100%的数据,N<=10000,T<=7Source
【思路】转化+hash+线段树。
首先需要明确的一点:A是一个1..n的排列。
其次将出现情况统计为01字符串分别表示该数字目前为止是否出现,因此对于一个数字当前没有出现以后一定会出现。例如对于{5,2,1,4,3,6}且已经扫到了4,则有01状态为110010,可以看出如果有一对数字以4为中心分别为01则一定有等差数列。又因为非0即1的性质,所以问题可以转化为两个字串是否相等的问题,对应到例子中即s(2,3)是否等于s(6,5),如果相等则必无等差数列反之则必有一个或多个等差数列。
线段树维护hash,[区间查询单点修改],O(logn)的查询时间,O(logn)的维护时间,总时间为O(nlogn)。
注:求Hash对应一个区间查询。
【代码】
#include<cstdio> #include<cstring> #include<iostream> #define FOR(a,b,c) for(int a=(b);a<=(c);a++) using namespace std; typedef long long LL; const int maxn = 10000+10; const int MOD = 100000007; int read() { char c=getchar(); while(!isdigit(c)) c=getchar(); int x=0; while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } return x; } int n; int a[maxn],xp[maxn]; LL sumv[4*maxn][2]; int v; void update(int u,int L,int R) { int lc=u<<1,rc=lc+1; if(L==R) { sumv[u][0]=sumv[u][1]=1; } else { int M=L+(R-L)/2; if(v<=M) update(lc,L,M); else update(rc,M+1,R); sumv[u][0]=(sumv[rc][0]+xp[R-M]*sumv[lc][0]%MOD)%MOD; sumv[u][1]=(sumv[lc][1]+xp[M-L+1]*sumv[rc][1]%MOD)%MOD; } } LL query(int node,int l,int r,int a,int b,int x){ int lc=node<<1,rc=lc+1; if(l==a&&r==b)return sumv[node][x]; int m=(l+r)>>1; LL left=0,right=0; if(m<b)right=query(rc,m+1,r,max(m+1,a),b,x); if(a<=m)left=query(lc,l,m,a,min(m,b),x); return (x?left+right*xp[max(0,m-a+1)]%MOD:right+left*xp[max(0,b-m)]%MOD)%MOD; } int main() { freopen("cin.in","r",stdin); freopen("coutme.out","w",stdout); int T; T=read(); while(T--) { memset(sumv,0,sizeof(sumv)); n=read(); xp[0]=1; FOR(i,1,n+5) xp[i]=(xp[i-1]<<1)%MOD; FOR(i,1,n) a[i]=read(); bool f=0; FOR(i,1,n) { int x=a[i]; LL lf,rf; int len=min(x-1,n-x); if(len&&query(1,1,n,x-len,x-1,0)!=query(1,1,n,x+1,x+len,1)){ f=1; break; } v=x; update(1,1,n); } if(f) printf("Y\n"); else printf("N\n"); } return 0; }
相关文章推荐
- 关于设置UILabel的文本缩进
- 从最大似然到EM算法浅解
- 同样版本的jstl,都是jstl1.2版本,有个有问题,另一个没有问题
- vim简单的文本编辑命令
- [AlwaysOn Availability Groups]AlwaysOn健康诊断日志
- Deep Learning(深度学习)学习笔记整理系列之(八)
- 在Ubuntu 14.04 64bit上使用JBL Charge2+无线蓝牙音箱听歌指南
- Android dumpsys 命令解析
- fedora22 安装fcitx 输入法
- grub2 设置Windows为默认启动系统
- Deep Learning(深度学习)学习笔记整理系列之(七)
- view.setTag()和view.getTag()
- AFS结束使命新产品FMS上市
- Win8系统下安装Oracle11g时,安装程序报错:[INS-13001]环境不满足最低要求解决方法
- Deep Learning(深度学习)学习笔记整理系列之(六)
- 怎样成长为一个优秀的web前端工程师
- 设置win版vim启动项[利刃篇]
- 用户不在sudoers文件中的解决方法
- Deep Learning(深度学习)学习笔记整理系列之(五)
- 第七章 高级排序