bzoj2124
bzoj2124
题目大意 :
在一个很长(1e5)的串里面找一个长度为三的等比子序列
考虑枚举中间值,想办法在lg的复杂度下解决单次枚举,初次考虑为依次比较中间值+d和中间值-d是否出现在这个值的前面和后面
这里可以通过映射On完成,但是复杂度仍然达不到要求,然后我们考虑到这是一个排列,也就是说那些数字出现且仅出现一次,那我
们用一个01数列来维护某个值是否出现在枚举值的前面和后面,这里假设出现在前面为0,后面为1,那什么时候最终答案是yes呢,当
且仅当关于某个中间值+d和这个中间值-d在01数列中恰好一个为0一个为1,也就是说不相同,这里还是很复杂,我们考虑把01数列当作
一个大数,那答案是yes就意味着这个大数关于中间值没有局部回文,好!现在我们暂停深入分析,总结一下,首先我们在枚举中间值
构建01数列,然后我们在01数列中寻找关于中心值的局部回文是否不存在。再进一步分析:枚举中间值的过程中,01数列在做单点修改
查询局部回文是否不成立的过程可以直接用字符串hash解决,题目到此已经解决。解法:线段树维护01数列正反hash值,如何正反?构
造一个反向01数列,用俩线段树就行了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define ls (u<<1) #define rs (u<<1|1) #define ml ((l+r)>>1) #define mr (ml+1) struct segment_tree{ const static ll maxn=2.1e4; const static ll MOD=1e9+7; static ll pow_2[maxn]; ll n; ll tree[maxn<<2]; static void pow_ini(){ pow_2[0]=1; for(int i=1;i<maxn;i++){ pow_2[i]=pow_2[i-1]*2; if(pow_2[i]>MOD)pow_2[i]-=MOD; } } void pushup(ll l ,ll r,ll u){ tree[u]=(tree[ls]*pow_2[r-((l+r)>>1)]+tree[rs])%MOD; } void build(ll nn){ n=nn; build(1,n,1); } void build(ll l,ll r,ll u){ if(l==r){ tree[u]=0; return ; } build(l,ml,ls); build(mr,r,rs); pushup(l,r,u); } void update(ll q,ll d){ update(q,d,1,1,n); } void update(ll q,ll d,ll u,ll l,ll r){ if(q<=l&&r<=q){ tree[u]=(tree[u]+d*pow_2[r-q])%MOD; return ; } if(q<=ml)update(q,d,ls,l,ml); if(q>=mr)update(q,d,rs,mr,r); pushup(l,r,u); } ll query(ll ql,ll qr){ return query(ql,qr,1,1,n)%MOD; } ll query(ll ql,ll qr,ll u,ll l,ll r){ if(ql<=l&&r<=qr)return tree[u]*pow_2[qr-r]%MOD; ll ret=0; if(ql<=ml)ret=ret+query(ql,qr,ls,l,ml); if(qr>=mr)ret=ret+query(ql,qr,rs,mr,r); return ret; } }t1,t2; ll segment_tree::pow_2[maxn]; const int maxn=segment_tree::maxn; int per[maxn]; int main(){ segment_tree::pow_ini(); int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",per+i); t1.build(n); t2.build(n); string ans="N"; for(int mid=1;mid<n-1;mid++){ t1.update(per[mid-1],1); t2.update(n+1-per[mid-1],1); int len=min(per[mid]-1,n-per[mid]); if(len==0)continue; if(t1.query(per[mid]-len,per[mid]-1)!=t2.query( n+1-(per[mid]+len) , n+1-(per[mid]+1) )){ ans="Y"; break; } } cout<<ans<<endl; } }
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Believe it!