luogu P1107 雷涛的小猫 题解
\quad 不难发现,这是一道 d p dp dp题。看完题后,很容易能想到以高度为阶段来进行 d p dp dp。那么,状态设置也可以顺水推舟地想到: d p i , j dp_{i,j} dpi,j表示在第 j j j棵树,高度为 i i i的地方可获得的最大柿子数。
\quad 然后,我们就可以考虑状态转移。我们可知:得到 d p i , j dp_{i,j} dpi,j的方式有两种,一是从 d p i + 1 , j dp_{i + 1,j} dpi+1,j转移来,二是从 m a x d p i + d e l t a , k ( k ∈ [ 1 ∼ n ] , k ≠ j ) max_{dp_{i+delta,k}(k\in[1\sim n],k\not =j)} maxdpi+delta,k(k∈[1∼n],k=j)转移来。如果硬按照这个转移式来写,不难发现,时间复杂度是 O ( n 2 h ) O(n^2h) O(n2h),显然会 T L E TLE TLE。那么我们就可以将取 m a x max max的步骤进行优化。但是本题解的优化方法与其他的可能有些许区别。
 
     
      
       
        
       
      
        \quad 
       
      
    想优化,最简单的就是另开一个数组记录高度为 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i时 
     
      
       
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           , 
          
         
           j 
          
         
        
       
      
        dp_{i,j} 
       
      
    dpi,j的最大值,在转移时直接调用。这一优化,本质还在于用前面已更新的来更新自己。然而,本题解的优化方法,本质是用已更新的自己来更新后面。也就是,在对 
     
      
       
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           , 
          
         
           j 
          
         
        
       
      
        dp_{i,j} 
       
      
    dpi,j进行转移时,顺便记录下最大值,然后用它去更新 
     
      
       
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           − 
          
         
           d 
          
         
           e 
          
         
           l 
          
         
           t 
          
         
           a 
          
         
           , 
          
         
           k 
          
         
        
       
         ( 
        
       
         k 
        
       
         ∈ 
        
       
         [ 
        
       
         1 
        
       
         ∼ 
        
       
         n 
        
       
         ] 
        
       
         , 
        
       
         k 
        
       
         ≠ 
        
       
         j 
        
       
         ) 
        
       
      
        dp_{i-delta,k}(k \in [1 \sim n],k\not = j) 
       
      
    dpi−delta,k(k∈[1∼n],k=j)。其实并没有太大区别……
\quad 具体细节见 C o d e : Code: Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2010;
int n, h, d;
int dp[maxn][maxn];
int a[maxn][maxn];
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
int main() {
    n = read(), h = read(), d = read();
    for(int i = 1; i <= n; i ++) {
        int x = read();
        for(int j = 1; j <= x; j ++)
            a[i][read()] ++;
    }
    for(int i = 1; i <= n; i ++)
        for(int j = 0; j <= h; j ++)
            dp[i][j] = a[i][j];//直接将a数组全部赋给dp数组
    for(int i = h; i >= 0; i --) {
        int maxx = -1, maxid;
        for(int j = 1; j <= n; j ++) {
            if(dp[j][i] > a[j][i]) {//是从别的树上跳过来的
                dp[j][i] = max(dp[j][i], dp[j][i + 1] + a[j][i]);//判断是从别的树上跳过来收益大,还是从这棵树的上一个高度跳过来收益大
                if(dp[j][i] > maxx) {//取最大值
                    maxx = dp[j][i];
                    maxid = j;
                }
                continue;
            }
            dp[j][i] += dp[j][i + 1];//从上一个高度跳下来
            if(dp[j][i] > maxx) {//取最大值
                maxx = dp[j][i];
                maxid = j;
            }
        }
        if(i >= d) {//用当前最大值去更新后面的
            for(int j = 1; j <= n; j ++) {
                if(j != maxid) dp[j][i - d] += maxx;
            }
        }
    }
    int maxx = -1;
    for(int i = 1; i <= n; i ++) maxx = max(maxx, dp[i][0]);
    printf("%d", maxx);
    return 0;
}
                

                
            
        
浙公网安备 33010602011771号