神仙题啊
题解:
显然每一趟是倒着往前捡。
首先把所有垃圾分开考虑:如果位置在
的垃圾是第
次被捡起来的,则对答案有
的贡献。原因考虑每次在已经捡起
个垃圾的情况下,捡起这个垃圾的增量。如果
,则一开始走到那里花费是
,回去的代价是
,总共
。否则,每单位距离会增加
的代价,路程是
,因此总共增量是
。
现在考虑要走
趟,相当于是你有
个第一次捡起的机会,
个第二次、
个第三次…依次类推,要给每个垃圾分配是第几个被捡起的。显然
越大则
越小越好,也就是从远到近的分配1,2,…,前缀和优化一下即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ldb long double
#define lint long long
#define N 200010
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int a[N];lint s[N];
inline lint S(int a,int b) { return s[b]-s[max(a-1,0)]; }
int main()
{
int n=inn(),X=inn();rep(i,1,n) s[i]=s[i-1]+inn();
a[1]=5;rep(i,2,n) a[i]=2*i+1;ldb ans=1e100;
rep(k,1,n)
{
ldb s=0ll;
for(int i=n,j=1;i>0;i-=k,j++)
s+=a[j]*S(i-k+1,i);
ans=min(ans,s+(lint)X*(n+k));
}
return !printf("%lld\n",(lint)ans);
}