题解 P6563 【[SBCOI2020] 一直在你身旁】
2022.07.05 改了一个 typo。
突然发现有这题,推荐一做。
和出题者谈话后觉得我应该要提前4年退役了。
暴力就不说了。
\texttt{Subtask 2 }
如果数在一个区间
设计状态
复杂度
namespace subtask2 {
int f[509][509];
void main(){
memset(f,0x3f,sizeof(f));
per(l,n,1) rep(r,l,n) {
if(l==r) f[l][r]=0;
else if(r-l==1) f[l][r]=a[l];
else rep(k,l,r-1) f[l][r]=min(f[l][r],max(f[l][k],f[k+1][r])+a[k]);
}
printf("%lld\n",f[1][n]);
}
}
\texttt{Subtask 2 }
这个决策
把决策和答案打印出来,发现……
(大样例的样例2的第三个数据
...
7 9 8 15
7 10 8 17
7 11 9 24
7 12 10 27
7 13 9 32
7 14 10 35
7 15 11 38
...
决策没有特别规律。
再看看式子,
但是,这个
稍微思考一下得知,由于上面打表(和思考)得知,
现在有 3 步,找到分界点,讨论
Step 1 找到分界点
这里有单调性!
对于
Step 2 计算
这种情况,原式化为
Step 3 计算
这个少许麻烦了一些。原式化为
按照最朴素的单调队列维护即可,不需要什么分类讨论。(如果单调队列不会写的,建议抛弃这道题去学习单调队列)。
namespace ac {
int f[7009][7009],q[7009];
void main() {
rep(r,2,n) {
int p=r;
int ll=1,rr=2; q[1]=r;
per(l,r,1) {
if(l==r) {f[l][r]=0;continue;}
else if(r-l==1) {f[l][r]=a[l];continue;}
while(p>l&&f[p][r]<f[l][p-1]) p--; //Step1
f[l][r]=f[l][p]+a[p]; //Step2
while(ll<rr&&q[ll]>=p) ll++; //Step3 (and the next 3 lines)
if(ll<rr) f[l][r]=min(f[l][r],f[q[ll]+1][r]+a[q[ll]]);
while(ll<rr&&f[q[rr-1]+1][r]+a[q[rr-1]]>=f[l+1][r]+a[l]) rr--;
q[rr++]=l;
}
}
printf("%lld\n",f[1][n]);
}
}
尽管代码不长,但做的真的累。