1 条题解
-
0
自动搬运
来自洛谷,原作者为

b6e0_
搬运于
2025-08-24 22:29:43,当前版本为作者最后更新于2021-01-28 22:09:36,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
官方题解。
upd 2021.3.7:将 的下标改成括号形式,避免了下标不清。
这题赛时 AC 人数甚至没有压轴鱼神的多项式题人多?
把式子的前几项和后几项写出来:
$$(a_{p(1)}-a_{p(0)})(p(l+1)-p(l))+(a_{p(2)}-a_{p(1)})(p(l)-p(l-1))+\cdots+(a_{p(l)}-a_{p(l-1)})(p(2)-p(1))+(a_{p(l+1)}-a_{p(l)})(p(1)-p(0)) $$很难贪心,考虑 dp。发现状态中只记单独一个位置不好 dp,式子中 与 相关,再观察发现它们是两两对应的,于是将它们捆起来 dp,也就是选择 的元素时,左边选一个右边同时选一个。
设计状态 表示左边选到 ,右边选到 。转移方程是:
$$f_{i,j}=\max_{xj}\{f_{x,y}+(a_i-a_x)(y-j)+(a_y-a_j)(i-x)\} $$当然可以不转移,将 直接作为 的开头和结尾,即 。
将 求出来后,求出答案要分三种情况:
- ,此时直接枚举 即可;
- 为偶数,此时直接用 的值加上 与 之间产生的贡献 ;
- 为奇数,此时对于每一个 ,枚举 计算答案即可。
复杂度瓶颈在求 ,考虑优化。
将转移方程中的括号拆开:
$$f_{i,j}=\max_{xj}\{f_{x,y}+a_i\cdot y-a_i\cdot j-a_x\cdot y+a_x\cdot j+a_y\cdot i-a_y\cdot x-a_j\cdot i+a_j\cdot x\} $$将只与 有关的东西提出来:
$$f_{i,j}=\max_{xj}\{f_{x,y}+a_i\cdot y-a_x\cdot y+a_x\cdot j+a_y\cdot i-a_y\cdot x+a_j\cdot x\}-a_i\cdot j-a_j\cdot i $$枚举 ,将 也看作一个定值:
$$f_{i,j}=\max_{xj}\{a_x\cdot j+a_j\cdot x+f_{x,y}+a_i\cdot y-a_x\cdot y+a_y\cdot i-a_y\cdot x\}-a_i\cdot j-a_j\cdot i $$然后发现,与 有关的部分中只有 和 没有 。于是用 表示对于这对 最好的 产生的最大值,即:
$$g_{i,x}=\max_y\{f_{x,y}+a_i\cdot y-a_x\cdot y+a_y\cdot i-a_y\cdot x\} $$这个东西中包含一个 比较烦,考虑一边求 一边更新 。具体来说,枚举 ,在循环里要做这些事:
- 枚举 ,通过 快速计算 的值;
- 将 当做 中的 ,枚举 中的 ,更新 。
这段还是看程序比较好懂吧,可以先跳到下面程序部分搞懂再往下。
然后,还有一点细节要注意: 的式子里面 其实是要大于“”,但是不能把 记下来(不然就爆炸了),要通过一些手段使得当前 中存的都是大于 的答案。于是外层枚举 并倒序枚举。
还有一个小问题: 是不能转移到 的,但是如果内层循环 正序枚举,那么在 时更新了 ;在 时需要的有 ,其中 重复了,于是内层的 也要倒序循环。
时间复杂度 ,代码:
#include<bits/stdc++.h> using namespace std; long long a[305],f[305][305],g[305][305]; inline int read() { char c=getchar(); int x=0,y=1; while(c<'0'||c>'9') { if(c=='-') y=-1; c=getchar(); } while(c>='0'&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); } return x*y; } int main() { int n=read(),i,j,k; long long ans=-1000000000000000000ll; for(i=1;i<=n;i++) a[i]=read(); for(i=1;i<=n;i++) for(j=1;j<=n;j++) g[i][j]=-1000000000000000000ll; for(j=n;j;j--)//外层枚举j并倒序枚举,上面有解释 for(i=j-1;i;i--)//内层枚举i并倒序枚举,上面有解释 { f[i][j]=a[i]*(n-j+1)-a[j]*i;//不转移的情况 for(k=1;k<i;k++)//这里的k就是转移方程中的x f[i][j]=max(f[i][j],g[i][k]-a[i]*j+a[k]*j-a[j]*i+a[j]*k); ans=max(ans,f[i][j]+(a[j]-a[i])*(j-i)); for(k=i+1;k<j;k++)//这里的k就是g[i][x]中的i g[k][i]=max(g[k][i],f[i][j]+a[k]*j-a[i]*j+a[j]*k-a[j]*i); } for(i=1;i<=n;i++) ans=max(ans,a[i]*(n-i+1)-a[i]*i); for(i=1;i<n;i++) for(j=i+1;j<=n;j++) for(k=i+1;k<j;k++) ans=max(ans,f[i][j]+(a[k]-a[i])*(j-k)+(a[j]-a[k])*(k-i)); printf("%lld",ans); return 0; }
- 1
信息
- ID
- 6438
- 时间
- 200ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者