三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

[AGM 2022 资格赛] 分裂 题解

[AGM 2022 资格赛] 分裂 题解

[AGM 2022 资格赛] 分裂 题解

洛谷链接,记得点赞

前言

一道十分有意思的小题。

分析

观察这个式子,可以考虑使用 DP。

d p i , j dp_{i,j}dpi,j表示前i ii个元素,已经划分了j jj非空子段的最大得分。

直接写出状态转移:
d p i , j = max ⁡ k = j − 1 i − 1 ( d p k , j − 1 + [ max ⁡ p = k + 1 i ( a p ) ] b j − [ min ⁡ p = k + 1 i ( a p ) ] b j ) dp_{i,j}=\max_{k=j-1}^{i-1}(dp_{k,j-1}+[\max_{p=k+1}^i(a_p)]^{b_j}-[\min_{p=k+1}^i(a_p)]^{b_j})dpi,j=k=j1maxi1(dpk,j1+[p=k+1maxi(ap)]bj[p=k+1mini(ap)]bj)
显然,这是O ( n 4 ) O(n^4)O(n4)的时间复杂度,即使使用 ST 表优化查询,也会达到O ( n 3 ) O(n^3)O(n3),会超时。

仔细一看,发现转移只跟最大值最小值有关。

所以答案就成了选择K KK个点对的最大得分。

状态定义

d p i , j , k dp_{i,j,k}dpi,j,k表示前i ii个元素,已经开始划分第j jj非空子段,状态为k kk的最大得分。

其中,k kk的含义为:

  • k = 0 k=0k=0,则表示所有的点对已经配对
  • k = 1 k=1k=1,则表示仅配对了最大值。
  • k = 2 k=2k=2,则表示仅配对了最小值。

根据定义,答案就是d p n , K , 0 dp_{n,K,0}dpn,K,0

状态转移

显然,选取最大值a i a_iai的贡献是a i b j a_i^{b_j}aibj,最小值的贡献是− a i b j -a_i^{b_j}aibj

对于每一个状态k kk,除了不选,有如下的转移路径:

  • k = 0 k=0k=0时,可以独成一段或从k = 1 k=1k=1或从k = 2 k=2k=2转移。
  • k = 1 k=1k=1k = 2 k=2k=2时,可以从闭合状态转移。
初始化

因为可能出现负数,显然需要将d p dpdp数组初始化为极小值。

此外,由于在枚举i ii时,k = 0 k=0k=0时转移会访问到d p i , 0 , 0 dp_{i,0,0}dpi,0,0,所以需要初始化d p i , 0 , 0 dp_{i,0,0}dpi,0,00 00

参考代码

#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,k;inta[5010],b[5010];intdp[3][5010][5];intfpow(intx,inty){intres=1;while(y){if(y&1)res*=x;x*=x;y>>=1;}returnres;}signedmain(){memset(dp,0xc0,sizeof(dp));cin>>n>>k;for(inti=1;i<=n;i++){cin>>a[i];}for(inti=1;i<=k;i++){cin>>b[i];}for(inti=0;i<=n;i++){dp[i][0][0]=0;}for(inti=1;i<=n;i++){for(intj=1;j<=min(k,i);j++){dp[i&1][j][0]=max({dp[(i-1)&1][j][0],dp[(i-1)&1][j-1][0],dp[(i-1)&1][j][1]-fpow(a[i],b[j]),dp[(i-1)&1][j][2]+fpow(a[i],b[j])});dp[i&1][j][1]=max({dp[(i-1)&1][j][1],dp[(i-1)&1][j-1][0]+fpow(a[i],b[j])});dp[i&1][j][2]=max({dp[(i-1)&1][j][2],dp[(i-1)&1][j-1][0]-fpow(a[i],b[j])});//要么不选,要么选}}cout<<dp[n&1][k][0];return0;}

by lonys

← 返回列表