UOJ #246. 【UER #7】套路
题面传送门
首先容易发现一个性质:答案不超过\(m\)。
因为\(s(l,r)\)表示\([l,r]\)中最小的间隔,再乘上\(r-l\)一定不会超过\(m\)。
这启发我们根号分治。
对于长度小于\(\sqrt m\)的区间,每次维护set暴力拓展,计算答案,时间复杂度\(O(n\sqrt m\log n)\)
对于长度大于\(\sqrt m\)的区间,则\(s(l,r)\leq \sqrt m\)。那么可以枚举\(s(l,r)\)的值并计算不小于这个值的区间,可以two-points+set维护,时间复杂度也是\(O(n\sqrt m\log n)\)
这个根号带log感觉很逊,于是我们可以去log。
首先看第一部分,容易发现直接根据上一次的\(\sqrt m\)个区间的询问直接拓展可以得到现在区间的答案。
然后看第二部分,发现答案不小于当前值等价于对于每个\(i\),所有\(|A_i-A_j|\leq B\)的\(j\)不能共存,\(j\)又是每次增加\(1\)的,所以可以用一个桶维护最近的这个值,然后前缀max可以做到\(O(n\sqrt m)\)
所以总时间复杂度被优化到\(O(n\ sqrt m)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (200000+5)
#define M (100+5)
#define K (1000+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,k,m,P,A[N],Fl[N],Ans,G[K],ToT,H[K];
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d%d",&n,&m,&P);k=sqrt(m);for(i=1;i<=n;i++) scanf("%d",&A[i]);Me(G,0x3f);
for(i=1;i<=n;i++)for(Mc(H,G),j=1;j<=min(k,i-1);j++) G[j]=min(H[j-1],min(G[j-1],abs(A[i]-A[i-j]))),j>=P-1&&(Ans=max(Ans,j*G[j]));Me(G,0);
for(i=1;i<=n;Fl[A[i]]=i,i++)for(j=0;j<=m/k;j++) j&&(G[j]=max(G[j],G[j-1])),A[i]+j<=m&&(G[j]=max(G[j],Fl[A[i]+j])),A[i]-j>=0&&(G[j]=max(G[j],Fl[A[i]-j])),i-G[j]>=P&&(Ans=max(Ans,(j+1)*(i-G[j]-1)));printf("%d\n",Ans);
}