正题
题目大意:https://www.luogu.org/problemnew/show/P4945
题目大意
第isi\ si s可以
- 获取1∼i1\sim i1∼i中最大的能量
- 获取1∼i1\sim i1∼i中类型为xix_ixi的能量
- 下一秒能量加倍(只能使用mmm次,不可以连续使用)
求最大获取能量
解题思路
考虑dpdpdp,定义fi,j,kf_{i,j,k}fi,j,k表示第isi\ si s和使用了jjj次加倍,这次是否使用加倍
首先我们如果获取能量肯定是选择111和222操作中最多的那个,
定义w=max{max{pj}(j≤i),∑j=1ipj∗(kj==xi)}w=max\{max\{p_j\}(j\leq i),\sum_{j=1}^ip_j*(k_j==x_i)\}w=max{max{pj}(j≤i),j=1∑ipj∗(kj==xi)}
第一个好求,第二个我们可以用离散化
然后开始dpdpdp,如果这次使用魔法
fi,j,1=fi−1,j−1,0f_{i,j,1}=f_{i-1,j-1,0}fi,j,1=fi−1,j−1,0
然后如果获取能量
fi,j,0=max{fi−1,j,0+w,fi−1,j,1+2∗w}f_{i,j,0}=max\{f_{i-1,j,0}+w,f_{i-1,j,1}+2*w\}fi,j,0=max{fi−1,j,0+w,fi−1,j,1+2∗w}
时间复杂度:O(2nm)O(2nm)O(2nm)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e4+10,M=510;
int n,m,k[N],p[N],x[N],len;
int ans,b[N],w[N],f[N][M][2],maxs;
int main()
{//f[i][j][0/1]表示第i秒,还剩下j个加倍,上一秒是否使用了魔法scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d%d",&k[i],&p[i]);b[i]=k[i];} sort(b+1,b+1+n);len=unique(b+1,b+1+n)-b-1;for(int i=1;i<=n;i++){scanf("%d",&x[i]);int check=x[i];x[i]=lower_bound(b+1,b+1+len,x[i])-b;if(check!=b[x[i]]) x[i]=0;k[i]=lower_bound(b+1,b+1+len,k[i])-b;}memset(f,0xcf,sizeof(f));f[0][0][0]=0; for(int i=1;i<=n;i++){maxs=max(maxs,p[i]);w[k[i]]+=p[i];int z=max(maxs,w[x[i]]);for(int j=0;j<=m;j++){if(j!=0) f[i][j][1]=f[i-1][j-1][0];f[i][j][0]=max(f[i-1][j][0]+z,f[i-1][j][1]+2*z);if(i==n)ans=max(ans,max(f[i][j][1],f[i][j][0]));}}printf("%d",ans);
}