P2757 [国家集训队] 等差子序列 题解
很巧妙的一道题,看到标签的时候想到始终想不到怎么用到哈希,但仔细分析出来后又发现每一步都还算环环相扣,于是写一篇题解。
根据题目,我们要找长度大于等于 \(3\) 的的等差序列,不难发现如果有长度大于 \(3\) 的等差序列,必然有长度等于 \(3\) 的等差序列,那我们只要找长度等于 \(3\) 的等差序列就行了,简化了问题。
考虑这样的序列有什么性质,首先,我们令中间的数为 \(a\),那么存在一个 \(x\) 使 \(a-x,a,a+x\) 构成这个合法序列,由于每一个数作为中间的数都是可能的,在枚举中间数这个过程是不能优化的,考虑怎么去找两边的数。
由于原序列是一个排列,每个数都只会出现一次,那么我们是可以在枚举到 \(a\) 时得知哪些数出现过,哪些数没有的,考虑将这个出现关系表示为 \(01\) 序列,表示令排列的长度为 \(n\),对于 \(a\) 的位置 \(i\),我们需要考虑的序列是以 \(i\) 为中心向两边延申到边界停止的所有的数构成的,如对于 \(n=7,i=5\) 序列的范围就是 \(3\) 到 \(7\)。
在这样一个关系里,关于 \(i\) 对称的两个数 \(i-k,i+k\) 若都为 \(1\) 或 \(0\) 说明它们都在 \(i\) 的左边或右边,是不合法的,若要满足整个序列所有关于 \(i\) 对称的数都不合法,那么这个序列是一个回文串。如何快速判断回文?这就用到哈希了,至于修改哈希和查询哈希就用到了线段树,那么这道题就在 \(O(n\log n)\) 的时间内解决了。
机房神犇说这道题好像卡自然溢出?但好像没卡?
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Hash=13331;
const int P=1e9+7;
const int N=5e5+10;
struct SG{
int l,r;
int sum;
}tr1[N<<2],tr2[N<<2];
int T;
int n;
int a[N];
int h[N];
void pushup(int u){
tr1[u].sum=(tr1[u<<1].sum*h[(tr1[u<<1|1].r-tr1[u<<1|1].l+1)]%P+tr1[u<<1|1].sum)%P;
tr2[u].sum=(tr2[u<<1|1].sum*h[(tr2[u<<1].r-tr2[u<<1].l+1)]%P+tr2[u<<1].sum)%P;
}
void build(int u,int l,int r){
tr1[u].l=tr2[u].l=l;
tr1[u].r=tr2[u].r=r;
if(l==r){
tr1[u].sum=0;
tr2[u].sum=0;
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int x){
if(tr1[u].l==x&&tr1[u].r==x){
tr1[u].sum=1;
tr2[u].sum=1;
return ;
}
int mid=tr1[u].l+tr1[u].r>>1;
if(x<=mid) modify(u<<1,x);
if(x>mid) modify(u<<1|1,x);
pushup(u);
}
int query1(int u,int l,int r){
if(l==tr1[u].l&&r==tr1[u].r){
return tr1[u].sum;
}
int mid=tr1[u].l+tr1[u].r>>1;
if(r<=mid){
return query1(u<<1,l,r);
}
else if(l>mid){
return query1(u<<1|1,l,r);
}
else{
return (query1(u<<1,l,mid)*h[r-mid]%P+query1(u<<1|1,mid+1,r))%P;
}
}
int query2(int u,int l,int r){
if(l==tr2[u].l&&r==tr2[u].r){
return tr2[u].sum;
}
int mid=tr2[u].l+tr2[u].r>>1;
if(r<=mid){
return query2(u<<1,l,r);
}
else if(l>mid){
return query2(u<<1|1,l,r);
}
else{
return (query2(u<<1,l,mid)+query2(u<<1|1,mid+1,r)*h[mid-l+1]%P)%P;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin>>T;
h[0]=1;
for(int i=1;i<=5e5;i++){
h[i]=h[i-1]*Hash%P;
}
while(T--){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);
int flag=0;
for(int i=1;i<=n;i++){
modify(1,a[i]);
if(a[i]==1||a[i]==n){
continue;
}
int l,r;
if(a[i]<=n/2){
l=1;
r=(a[i]+(a[i]-l));
}
else{
r=n;
l=(a[i]-(r-a[i]));
}
if(query1(1,l,r)!=query2(1,l,r)){
flag=1;
break;
}
}
if(flag==1){
cout<<"Y"<<endl;
}
else{
cout<<"N"<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号