Description
给出n个数(<=n),设S(i,j)为i到j之间的两两数的绝对值最小值,求S(l,r)∗(r−l)(r-l+1>=k)的最大值。
Solution
设K为选K个数,
先想一下枚举K怎么做,很显然要先求出S,
设f[i][j]为做到第i个,往前选j个的S值,有DP:fi,j=min(fi−1,j−1,fi,j−1,|ai−ai−j+1|)
再想一下如果K非常大,
那么S的值一定不会很大,所以我们就可以枚举S的值,看看往前最多可以选到哪,
现在我们要求以当前点i作为结尾的S=j的区间,最长有多长;
记录一下la[j]表示j这个数最后出现的位置,ca[j]表示所有S=j的区间中,区间的开头出现的最晚的位置,
枚举j,伴随着j的增大,区间的左端点l的位置一定越来越大,
要使当前的区间S=j,就要在上一个区间(S=j-1)算出的l的基础上,往后移,
那么就要使当前的区间不得使l<=min(la[ai+j−1],la[ai−j+1]),也不得使l<=ca[j−1],
所以取一个max即可。
我们发现当k=n√时,复杂度最优为O(nn√)。
复杂度:O(nn√)
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define foi(i,a,b) for(i=a;i<=b;i++)
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=200500,INF=2147483640;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans,m1,M;
int a[N],f[2][N];
int la[N*2],ca[N];
int main()
{
int q,w;
read(n),read(m1),read(m);M=666;m--;
fo(i,1,n)read(a[i]),f[1][i]=N;
fo(I,2,M)fo(i,I,n)
w=(I+1)%2,ans=max(ans,(I>m)*(I-1)*(f[I%2][i]=min(f[w][i],min(f[w][i-1],abs(a[i]-a[i-I+1])))));
la[a[1]]=1;
fo(i,2,n)
{
q=1;
fo(j,0,min(m1,M))
{
if(i-q+1>m)ans=max(ans,j*(i-q));
if(a[i]>j&&la[a[i]-j])q=max(q,la[a[i]-j]),ca[j]=max(ca[j],la[a[i]-j]);
ca[j]=max(ca[j],la[a[i]+j]);
q=max(q,max(ca[j]+1,la[a[i]+j]));
}
la[a[i]]=i;
}
printf("%d\n",ans);
return 0;
}