链接:https://ac.nowcoder.com/acm/contest/942/D
来源:牛客网
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld
题目描述
小A出了一道只有题目和计算几何有关的题
给出整数数组A,求长度大于等于L的连续子段中,平均数最大的那个。输出平均数。
输入描述:
输出描述:
一行一个数表示答案,你的答案正确当且仅当和标准答案误差不超过10−6
示例1
输入
5 2
3 7 5 5 16
输出
-0.50000000
说明
序列为3,−4,−4,−7,0
备注:
对于10%10%的数据,L=1L=1
对于20%20%的数据,n≤1000n≤1000
对于40%40%的数据,n≤105n≤105
对于另外20%20%的数据,m≤10,L≤105m≤10,L≤105
对于100%100%的数据,1≤L≤n≤1071≤L≤n≤107,1≤a1,x,y,z,m≤1091≤a1,x,y,z,m≤109,mm为偶数
和POJ 2018 相仿
利用斜率优化 求解
参考2004年论文 周源--浅谈数形结合思想在信息学竞赛中的应用.
取Pt点之前凸包的最大斜率处,
删除之前点
将和Pt距离为L的点加入
删除前面不符合的点
在q数组中的是当前凸包的位置,
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e7+15;
ll a1,x,y,z,m;
ll n,L;
ll a[maxn];
ll sum[maxn];
int q[maxn];
double slope(int u,int v)
{
return (double)(sum[u]-sum[v])/(u-v);
}
void create()
{
scanf("%lld%lld",&n,&L);
scanf("%lld%lld%lld%lld%lld",&a1,&x,&y,&z,&m);
a[1]=a1;
for(int i=2;i<=n;i++)
{
a[i]=((x*a[i-1]%m*a[i-1]%m+y*a[i-2]%m+z)%m+m)%m-m/2;
}
// for(int i=1;i<=n;i++)
// {
// printf("%lld ",a[i]);
// }
}
void solve()
{
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];//前缀和 平均数 类似斜率
}
double ans=-1e12;
int head=0,tail=1;
q[head]=0;
for(int i=L;i<=n;i++)
{
while(head+1<tail&&slope(q[head],q[head+1])<slope(q[head]+1,i))//保证满足凸包性质
head++;
ans=max(ans,slope(q[head],i));
int in=i-L+1;//保证最短长度L
while(head+1<tail&&slope(q[tail-1],q[tail-2])>slope(q[tail-1],in))//得到以L为最小距离的凸包
tail--;
q[tail]=in;
tail++;
}
printf("%.10f",ans);
}
int main()
{
create();
solve();
return 0;
}