题解 P6563 【[SBCOI2020]一直在你身旁】
JohnVictor · · 题解
首先有个
枚举区间长度,或者倒序枚举
考虑优化,爆推式子好像有点难,那么观察式子,里面有一个
想到这里,接下来的部分就顺理成章了,分类讨论中转点
(1)vector 优化到
(2)
代码不长,即使手写单调队列优化常数都只有 30 行。关于常数方面,区间 dp 中由于倒序枚举的特殊性,所有 dp[l][r] 写成 dp[r][l] 能快
代码还是放下,主要是 @xiaoyaowudi 写的。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
#define rl register long long
#define N 7010
ll a[N],f[N][N],n,t;
struct my_deque{
ll dat[N];int l,r;
inline void clear(){l=r=0;}
inline void push_back(rl a){dat[r++]=a;}
inline void pop_back(){--r;}
inline void pop_front(){++l;}
inline bool empty(){return l==r;}
inline int front(){return dat[l];}
inline int back(){return dat[r-1];}
}qe;
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld",&n);
for(rl i=1;i<=n;++i)
scanf("%lld",&a[i]);
for(int j=2;j<=n;++j){
qe.clear();
qe.push_back(j-1);
f[j][j-1]=a[j-1];
for(int i=j-2,l=j;i;--i){
while(f[l-1][i]>f[j][l] && l>i) --l;
while(!qe.empty() && l<=qe.front()) qe.pop_front();
f[j][i]=a[l]+f[l][i];
if(!qe.empty()) f[j][i]=min(f[j][i],f[j][qe.front()+1]+a[qe.front()]);
while(!qe.empty() && a[qe.back()]+f[j][qe.back()+1]>=a[i]+f[j][i+1]) qe.pop_back();
qe.push_back(i);
}
}
printf("%lld\n", f[n][1]);
}
return 0;
}
关于乱搞:
值得一提的是,如果令
并且,