原本覺得作法同樣,就是少帶個$log$,結果發現看不懂出題人的題解(我好菜啊)
那就本身寫一篇吧
比較簡單的$DP$思路
狀態定義:
前兩個轉移很好處理,第三個好像就很差辦了
不妨暴力定義進狀態裏
設$dp[i][j]$表示前$i$秒用了$j$次第三種轉移的最大能量和
轉移:
三種轉移
$(i'<i)$
$1,dp[i][j]=max(dp[i][j],dp[i-1][j]+max\left\{p[i']\right\})$
$2,dp[i][j]=max(dp[i][j],dp[i-1][j]+\sum_{k[i']=k[i]}p[i'])$
$3,dp[i][j]=max(dp[i][j],dp[i-2][j-1]+2*max(max\left\{p[i]\right\},\sum_{k[i']=k[i]}p[i']))$
考慮搞出來這兩個東西
$1,max\left\{p[i']\right\}$
前綴最大值便可$O(1)$
$2,\sum_{k[i']=k[i]}p[i']$
我寫的離散化而後每次用就是$O(1)$
$map$也能夠,可是用$map$的話,切記,對於相同的$i$,上式的值是相同的,不要放到枚舉$j$的內層循環了
ios
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int maxn=50010; int dp[maxn][510],n,m,k[maxn],p[maxn],x[maxn],mp[2*maxn],maxa,cnt,sum[2*maxn]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d",&k[i],&p[i]); mp[++cnt]=k[i]; } for(int i=1;i<=n;i++) scanf("%d",&x[i]),mp[++cnt]=x[i]; sort(mp+1,mp+cnt+1); cnt=unique(mp+1,mp+cnt+1)-mp-1; for(int i=1;i<=n;i++) { k[i]=lower_bound(mp+1,mp+cnt+1,k[i])-mp; x[i]=lower_bound(mp+1,mp+cnt+1,x[i])-mp; } for(int i=1;i<=n;i++) { maxa=max(maxa,p[i]),sum[k[i]]+=p[i]; int tmp=max(maxa,sum[x[i]]); for(int j=0;j<=min(i,m);j++) { if(i>1&&j) dp[i][j]=max(dp[i][j],dp[i-2][j-1]+2*tmp); dp[i][j]=max(dp[i][j],dp[i-1][j]+tmp); } } int ans=0; for(int i=0;i<=m;i++) ans=max(ans,dp[n][i]); printf("%d\n",ans); return 0; }