1 条题解

  • 0
    @ 2025-8-24 22:29:43

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar b6e0_

    搬运于2025-08-24 22:29:43,当前版本为作者最后更新于2021-01-28 22:09:36,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    官方题解。

    upd 2021.3.7:将 pp 的下标改成括号形式,避免了下标不清。

    这题赛时 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,式子中 iilil-i 相关,再观察发现它们是两两对应的,于是将它们捆起来 dp,也就是选择 pp 的元素时,左边选一个右边同时选一个。

    设计状态 fi,jf_{i,j} 表示左边选到 ii,右边选到 jj。转移方程是:

    $$f_{i,j}=\max_{xj}\{f_{x,y}+(a_i-a_x)(y-j)+(a_y-a_j)(i-x)\} $$

    当然可以不转移,将 {i,j}\{i,j\} 直接作为 pp 的开头和结尾,即 ai(nj+1)ajia_i(n-j+1)-a_j\cdot i

    ff 求出来后,求出答案要分三种情况:

    1. l=1l=1,此时直接枚举 p1p_1 即可;
    2. ll 为偶数,此时直接用 fi,jf_{i,j} 的值加上 iijj 之间产生的贡献 (ajai)(ji)(a_j-a_i)(j-i)
    3. ll 为奇数,此时对于每一个 fi,jf_{i,j},枚举 i<k<ji<k<j 计算答案即可。

    复杂度瓶颈在求 ff,考虑优化。

    将转移方程中的括号拆开:

    $$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\} $$

    将只与 i,ji,j 有关的东西提出来:

    $$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 $$

    枚举 xx,将 xx 也看作一个定值:

    $$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 $$

    然后发现,与 yy 有关的部分中只有 iixx 没有 jj。于是用 gi,xg_{i,x} 表示对于这对 (i,x)(i,x) 最好的 yy 产生的最大值,即:

    $$g_{i,x}=\max_y\{f_{x,y}+a_i\cdot y-a_x\cdot y+a_y\cdot i-a_y\cdot x\} $$

    这个东西中包含一个 fx,yf_{x,y} 比较烦,考虑一边求 ff 一边更新 gg。具体来说,枚举 i,ji,j,在循环里要做这些事:

    1. 枚举 xx,通过 gg 快速计算 fi,jf_{i,j} 的值;
    2. (i,j)(i,j) 当做 gg 中的 (x,y)(x,y),枚举 gg 中的 ii,更新 gg

    这段还是看程序比较好懂吧,可以先跳到下面程序部分搞懂再往下。

    然后,还有一点细节要注意:gg 的式子里面 yy 其实是要大于“jj”,但是不能把 jj 记下来(不然就爆炸了),要通过一些手段使得当前 gg 中存的都是大于 jj 的答案。于是外层枚举 jj 并倒序枚举。

    还有一个小问题:(i1,j)(i-1,j) 是不能转移到 (i,j)(i,j) 的,但是如果内层循环 ii 正序枚举,那么在 fi1,jf_{i-1,j} 时更新了 gi,i1,gi+1,i1g_{i,i-1},g_{i+1,i-1}\cdots;在 fi,jf_{i,j} 时需要的有 gi,i1,gi,i2g_{i,i-1},g_{i,i-2},其中 gi,i1g_{i,i-1} 重复了,于是内层的 ii 也要倒序循环。

    时间复杂度 O(n3)\mathcal O(n^3),代码:

    #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
    上传者