1. 程式人生 > 實用技巧 >Growth(後續效益持續作用,離散化dp)

Growth(後續效益持續作用,離散化dp)

題:https://ac.nowcoder.com/acm/problem/19809

題意:倆個屬性ai,bi,每天可以選擇任選一個屬性加1,有n件物品屬性:xi,yi,zi,當屬性ai>=xi&&bi>=yi,在接下來的每天中都會獲得zi的收益,問在m天中最多能收益多少(m<=2e8,xi,y1<=1e8,n<=1e3)

分析:

  • 先離散化;
  • 定義dp[i][j] 為屬性ai到達i,bj到達 j 時能夠獲得的最大代價;
  • 定義val[i][j]為屬性ai到達i,bj到達 j 時能夠獲得的代價和(記1天的代價);
  • 那麼dp[i][j]可以由dp[i-1][j], dp[i][j-1]轉化來,前者相差X[i]-X[i-1]-1天,也就是得到了(X[i]-X[i-1]-1)倍dp[i][j-1]的效益,同時加上一倍的val [i][j],後者也同理;
  • 最後更新答案,後面的m-X[i]-Y[j]有得“白嫖”;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int inf=0x3f3f3f3f;
const ll INF=(1ll<<40);
const int M=1e3+6;
struct node{
    ll x,y,z;
}a[M];
ll val[M][M],dp[M][M];
ll X[M],Y[M];
int tot;
int main(){
    
int n; ll m; scanf("%d%lld",&n,&m); for(int i=1;i<=n;i++){ ll x,y,z; scanf("%lld%lld%lld",&x,&y,&z); if(x+y>m) continue; a[++tot].x=x; a[tot].y=y; a[tot].z=z; X[tot]=x; Y[tot]=y; } sort(X
+1,X+1+tot); int totA=unique(X+1,X+1+tot)-X-1; sort(Y+1,Y+1+tot); int totB=unique(Y+1,Y+1+tot)-Y-1; for(int i=1;i<=n;i++){ int pos1=lower_bound(X+1,X+1+totA,a[i].x)-X; int pos2=lower_bound(Y+1,Y+1+totB,a[i].y)-Y; val[pos1][pos2]+=a[i].z; } for(int i=1;i<=totA;i++) for(int j=1;j<=totB;j++) val[i][j]+=val[i-1][j]+val[i][j-1]-val[i-1][j-1]; for(int i=1;i<=totA;i++) for(int j=1;j<=totB;j++){ dp[i][j]=val[i][j]+max(dp[i-1][j]+(X[i]-X[i-1]-1)*val[i-1][j],dp[i][j-1]+(Y[j]-Y[j-1]-1)*val[i][j-1]); } ll ans=0; for(int i=1;i<=totA;i++) for(int j=1;j<=totB;j++) if(X[i]+Y[j]<=m) ans=max(ans,(m-X[i]-Y[j])*val[i][j]+dp[i][j]); printf("%lld\n",ans); return 0; }
View Code

  • 定義dp[i][j] 為屬性ai到達