P1107 [BJWC2008]雷涛的小猫

84 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情

题目:小猫可以从宿舍的阳台上跳到窗外任意一棵柿子树的树顶。之后,她每次都可以在当前位置沿着当前所在的柿子树向下跳 1 单位距离。当然,小猫的能力远不止如此,她还可以在树之间跳跃。每次她都可以从当前这棵树跳到另外的任意一棵,在这个过程中,她的高度会下降 Delta 单位距离。每个时刻,只要她所在的位置有柿子,她就可以吃掉。整个“吃柿子行动”一直到小猫落到地面上为止。

雷涛调查了所有柿子树上柿子的生长情况。他很想知道,小猫从阳台出发,最多能吃到多少柿子?他知道写一个程序可以很容易的解决这个问题,但是他现在懒于写任何代码。于是,现在你的任务就是帮助雷涛写一个这样的程序。
思路:设f[i][j]表示高度为i在第j棵树上所能吃到的最多的柿子数,tx[i][j]高度为i在第j棵树上的柿子数,g[i]是高度为i最多可以吃多少柿子,那么转移方程就是

f[i][j]=max(f[i][j],f[i1][j]+tx[i][j])f[i][j]=max(f[i][j],g[id]+tx[i][j])(i>=d)f[i][j]=max(f[i][j],f[i-1][j]+tx[i][j]) \\ f[i][j]=max(f[i][j],g[i-d]+tx[i][j]) (i>=d)
#include<bits/stdc++.h>
//#pragma-GCC-optimize("-Ofast");
#define ll long long
//#define int long long
#define lowbit(x) ((x)&(-x))
#define endl '\n'
using namespace std;
const ll mod=998244353;
const ll inf=1e9;
const double pi=acos(-1);
const int N=1e6+100;
ll qpow(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
int n,h,d,f[2005][5005],g[2005],tx[2005][5005];
signed main()
{
    //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>h>>d;
    memset(tx,0,sizeof(tx));
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    for(int j=1;j<=n;j++){
        int m;cin>>m;
        for(int i=1;i<=m;i++){
            int x;cin>>x;
            tx[x][j]++;
        }
    }
    for(int i=1;i<=h;i++){
        for(int j=1;j<=n;j++){
            f[i][j]=max(f[i][j],f[i-1][j]+tx[i][j]);
            if(i>=d) f[i][j]=max(f[i][j],g[i-d]+tx[i][j]);
            g[i]=max(g[i],f[i][j]);
            //cout<<"f[i]="<<f[i][j]<<" f[i-1]="<<f[i-1][j]<<" g[i]="<<g[i]<<" tx[i][j]="<<tx[i][j]<<" i="<<i<<" j="<<j<<endl;
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,f[h][i]);
    cout<<ans<<endl;
    return 0;
}