挺有意思一道题
首先
n
2
n^2
n2 的
d
p
dp
dp 非常显然 考虑优化
复杂度不难想到大概是个分块
考虑一个显然的结论就是 如果
m
i
n
{
a
i
.
.
.
.
.
a
j
}
∗
(
i
−
j
)
2
>
n
∗
(
i
−
j
)
min\{a_i.....a_j\}*(i-j)^2>n*(i-j)
min{ai.....aj}∗(i−j)2>n∗(i−j) 的话 转移不如一个个跳 因此就不转移了
① 若
m
i
n
{
a
i
.
.
.
a
j
}
>
n
min\{a_i...a_j\}>\sqrt{n}
min{ai...aj}>n , 这种情况只要转移附近的
n
\sqrt{n}
n 即可
注意意思不是前面不转移了,因为对于更前面的
j
j
j 是有可能不满足条件的 这个属于后面的情况
② <
n
\sqrt{n}
n
有一个结论就是 如果
a
i
.
.
.
.
.
a
j
a_i.....a_j
ai.....aj 中最小值不在两端 ,那么显然从中间跳更优
那么只要维护一个小于
n
\sqrt{n}
n 的单调栈,只在栈内转移即可
可以简单讨论一下
a
i
a_i
ai 为最小或者
a
j
a_j
aj 最小的情况
做法就很显然了
如果
a
j
<
n
a_j < \sqrt{n}
aj<n 往前扫,扫到比自己大的就不转移了,然后同时从单调栈内所有的元素再转移一次
一开始我以为是排列
这里因为元素有重复 ,所以一定要加扫到比自己大的就不转移,以及单调栈是严格的= =
一开始写潦草了结果 TLE 了
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define ll long long
#define fr first
#define se second
#define mp make_pair
#define pb push_back
#define P pair<int,int>
int rd() {
int sum = 0;char c = getchar();bool flag = true;
while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
if(flag) return sum;
else return -sum;
}
int n;
int a[401000];
ll f[401000];
int st[401000];
int main() {
n = rd();
int K = (int)sqrt(n) + 1;
rep(i,1,n) a[i] = rd();
rep(i,2,n) f[i] = (long long) 2e18;
rep(i,2,n) {
int mn = a[i];
repp(j,i-1,max(1,i-K)) {
mn = min( mn , a[j] );
f[i] = min( f[i] , f[j] + 1ll*mn*(i-j)*(i-j) );
}
mn = a[i];
if( a[i] <= K )
repp(j,i-1,1){
mn = min( mn , a[j] );
f[i] = min( f[i] , f[j] + 1ll*mn*(i-j)*(i-j) );
if(a[j] <= a[i]) break;
}
repp(j,st[0],1) {
int id = st[j];
f[i] = min( f[i] , f[id] + 1ll*a[id]*(i-id)*(i-id) );
}
if( a[i] <= K ) {
while( a[i] < a[st[st[0]]] && st[0] > 0 ) st[0]--;
st[++st[0]] = i;
}
}
rep(i,1,n) printf("%lld ",f[i]);
return 0;
}