[暴力][线段树] Jzoj P4527 数列
题解
- 这题又可以水,对我这种懒人来说十分快乐 N^2过十万没什么好说的
- 下面讲讲正解,正解是线段树
- 首先我们先来看看对于一个满足要求的区间有什么条件:
- ①不存在相同的数
- ②所有的数在模d的意义下同余
- ③设max为区间最大值,min为区间最小值,应该满足:(max−min)/d−(i−j)<=k
- 这些应该都比较显然,就不解释了
- 我们可以先将在模d意义下同余的一段区间给弄出来
- 然后每句右端点
- 如果在同一个区间,维护左边的那个值的区间最小值
对于一个右端点可以影响到的位置,这个就可以用单调栈预处理最为最大最小值会影响到的位置
代码
1 #include <cstdio> 2 #include <iostream> 3 #define ll long long 4 using namespace std; 5 const int mo=19260817,N=2e5+10,p=37; 6 int n,k,d,l,r,pos,ans,a[N],pre[N],hash[mo+1][2]; 7 int calc(ll x,int d) 8 { 9 ll r=(x*p%mo+mo)%mo+1,s; 10 while (hash[r][0]&&hash[r][0]^x) r=r%mo+1; 11 hash[r][0]=x,s=hash[r][1],hash[r][1]=d; 12 return s; 13 } 14 int main() 15 { 16 scanf("%d%d%d",&n,&k,&d); 17 for (int i=1;i<=n;i++) scanf("%d",&a[i]),pre[i]=calc(a[i],i); 18 for (int i=1;i<n;i++) 19 { 20 l=r=a[i]; 21 for (int j=i+1;j<=n;j++) 22 { 23 if (pre[j]&&i<=pre[j]) break; 24 if ((a[j]-a[i])%d) break; 25 l=max(l,a[j]),r=min(r,a[j]); 26 if ((l-r)/d-(j-i)<=k) if (j-i+1>ans) ans=j-i+1,pos=i; else if (j-i+1==ans&&i<pos) pos=i; 27 } 28 } 29 printf("%d %d",pos,pos+ans-1); 30 }