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

wwlw
**搬运于
2025-08-24 22:04:46,当前版本为作者最后更新于2020-12-01 08:47:10,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文

Solution
比较套路的区间dp,先按坐标排序,再找出零点所在位置,记为 。设状态 表示取完区间 的所有水滴且最后位置在左边/右边的最大收益,但时间不好算,可以再开一个 来记录最优解转移到 时的时间,那么转移就很显然了。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define N 307 #define ll long long ll dp[N][N][2],t[N][N][2],a[N]; int n,m; int main(){ freopen("data.in","r",stdin); freopen("user.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+1+n+1); int pos; for(int i=1;i<=n+1;i++) if(!a[i]){pos=i;break;} memset(dp,-63,sizeof(dp)); dp[pos][pos][0]=dp[pos][pos][1]=0; t[pos][pos][0]=t[pos][pos][1]=m; ll ans=0; for(int l=2;l<=n+1;l++) for(int i=1,j=i+l-1;j<=n+1;i++,j++){ if(dp[i+1][j][0]+t[i+1][j][0]-(a[i+1]-a[i])>dp[i][j][0]){ dp[i][j][0]=dp[i+1][j][0]+t[i+1][j][0]-(a[i+1]-a[i]); t[i][j][0]=t[i+1][j][0]-(a[i+1]-a[i]); } if(dp[i+1][j][1]+t[i+1][j][1]-(a[j]-a[i])>dp[i][j][0]){ dp[i][j][0]=dp[i+1][j][1]+t[i+1][j][1]-(a[j]-a[i]); t[i][j][0]=t[i+1][j][1]-(a[j]-a[i]); } if(dp[i][j-1][1]+t[i][j-1][1]-(a[j]-a[j-1])>dp[i][j][1]){ dp[i][j][1]=dp[i][j-1][1]+t[i][j-1][1]-(a[j]-a[j-1]); t[i][j][1]=t[i][j-1][1]-(a[j]-a[j-1]); } if(dp[i][j-1][0]+t[i][j-1][0]-(a[j]-a[i])>dp[i][j][1]){ dp[i][j][1]=dp[i][j-1][0]+t[i][j-1][0]-(a[j]-a[i]); t[i][j][1]=t[i][j-1][0]-(a[j]-a[i]); } ans=max(ans,max(dp[i][j][0],dp[i][j][1])); } printf("%lld",ans); } /* 3 15 6 -3 1 */然后你就可以得到 分的高分。(这是我没有想到的)
上述做法的问题在于虽然 在当前是最优的,但是 可能已经被减得很小了,甚至是负的,对后面的转移不利(所以这直接就是个假作法)。转换思路,考虑费用提前算,枚举当前必选的水滴的个数,然后考虑进行dp。状态 变为在选完区间 且最后位置在左边/右边,能使得到水滴丢失的最少水分是多少,这个状态的实质是让上文的 尽量大,而对后面的状态产生正影响,那么这个算法的正确性就显然了。转移也很显然。那么对于不同的选取个数 ,分别进行一次dp后,答案就是
$$lim\times m-\min \limits_{1\leq l\leq l+lim-1\leq n}\{dp[l][l+lim-1]\} $$那么总的答案就是
$$\max \limits_{1\leq lim \leq n} \{lim\times m-\min \limits_{1\leq l\leq l+lim-1\leq n}\{dp[l][l+lim-1]\}\} $$复杂度
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define N 307 #define ll long long int n,m,pos=0; ll dp[N][N][2],a[N]; inline ll calc(int lim){ memset(dp,127,sizeof(dp)); dp[pos][pos][0]=dp[pos][pos][1]=0; for(int l=2;l<=lim;l++) for(int i=1,j=i+l-1;j<=n;i++,j++){ dp[i][j][0]=min(dp[i][j][0],min(dp[i+1][j][0]+(a[i+1]-a[i])*(lim-l+1),dp[i+1][j][1]+(a[j]-a[i])*(lim-l+1))); dp[i][j][1]=min(dp[i][j][1],min(dp[i][j-1][1]+(a[j]-a[j-1])*(lim-l+1),dp[i][j-1][0]+(a[j]-a[i])*(lim-l+1))); } ll ret=(1LL<<60); for(int i=1,j=i+lim-1;j<=n;i++,j++) ret=min(ret,min(dp[i][j][0],dp[i][j][1])); // printf("%lld\n",ret); return ret; } int main(){ // freopen("beetle.in","r",stdin); // freopen("beetle.out","w",stdout); scanf("%d%d",&n,&m); bool tag=0; for(int i=1;i<=n;i++) scanf("%lld",&a[i]),tag|=(!a[i]); if(!tag) n++; sort(a+1,a+1+n); for(int i=1;i<=n;i++) if(!a[i]){pos=i;break;} ll ans=-1; for(int i=1;i<=n;i++) ans=max(ans,i*m-calc(i)-(!tag? m:0)); printf("%lld",ans); } /* 3 15 6 -3 1 */Tips
原来的所有坐标中可能有 ,也可能没有。这会对答案产生影响,但简单讨论一下就可以了。
- 1
信息
- ID
- 3862
- 时间
- 4000ms
- 内存
- 16MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者