概述
题目描述
传送门
题解
算法一
直接上暴力。。。时间复杂度
O(n4)
,期望得分7分。
算法二
设
s(l,r)
表示l~r这一段两两差的最小值,那么可以递推:
s(l,r)=min(|al−ar|,min(s(l,r−1),s(l+1,r)))
。
求出
s(l,r)
了之后就可以暴力枚举了。时间复杂度
O(n2)
,期望得分20分。
这里的数组可以开成一维的,不过需要用一个特别的技巧:从后向前递推,数组里保留上一次递推的答案,那么
f[j]=min(f[j],f[j-1]),f[j]=min(f[j],Abs(a[j]-a[i]));其中第一次用f[j]来更新f[j]就是用上一次的答案来更新当前的答案。
算法三
由于m比较小,根据抽屉原理,一旦区间长度大于m,那么一定存在两个点相等,那么答案就为0了。所以我们只需要考虑区间长度<=m的部分,时间复杂度
O(nm)
。再结合算法二加点什么滚动数组之类的优化,期望得分40分。
算法四
设区间的长度为x,那么最小值不超过
mx−1
。
设一个常数
S
。
若x<=S,那么用算法三的方法,可以做到
若x>S,那么最小差不会超过
mS−1
。设
rx
表示权值为x的数最后出现的位置。每次新加入一个数
z
了之后,枚举差值
不过这里有很多需要注意的问题。首先是算区间的长度,区间中的元素个数当然是r-l+1,但是题目中所给的计算公式实际上是r-l。在算法四中,如果用f[i]来表示当前右端点为r时,左端点能到的最远点(不包括f[i]),那么最后计算答案的时候应该是i-f[i]-1,而且差值不应该是枚举的差值,而应该+1。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 200005
int n,m,k,S;
int a[N],f[N],r[N];
LL ans;
int Abs(int x)
{
return (x>0)?x:-x;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
S=sqrt(m);
memset(f,127,sizeof(f));
for (int i=n;i>=1;--i)
for (int j=i+1;j<=min(n,i+S-1);++j)
{
f[j]=min(f[j],f[j-1]);
f[j]=min(f[j],Abs(a[j]-a[i]));
if (j-i+1>=k)
ans=max(ans,(LL)f[j]*(j-i));
}
memset(f,0,sizeof(f));
for (int i=1;i<=n;++i)
{
for (int j=0;j<=m/S+1;++j)
{
if (j>=1) f[j]=max(f[j],f[j-1]);
if (a[i]-j>=1) f[j]=max(f[j],r[a[i]-j]);
if (a[i]+j<=m) f[j]=max(f[j],r[a[i]+j]);
if (i-f[j]>=max(k,S))
ans=max(ans,(LL)(i-f[j]-1)*(j+1));
}
r[a[i]]=i;
}
printf("%lldn",ans);
}
总结
最后
以上就是雪白鸵鸟为你收集整理的[UOJ#246][UER#7C]套路(数luan学gao相关)的全部内容,希望文章能够帮你解决[UOJ#246][UER#7C]套路(数luan学gao相关)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复