题解 P1107 【[BJWC2008]雷涛的小猫】
issue_is_fw · · 题解
这是你的福利题解,请签收>-<~
一、n^3方做法
1、根据问什么设什么的思想,我们很容易看出,题目中的状态有当前在那颗树,当前的高度。
那我们不妨设dp[i][j]为在i颗树高度为j时的最大吃苹果数。
2、我们发现,当处于第i棵树高度为j时,可以从第i棵树高度为j+1的地方掉下来,
即dp[i][j]=a[i][j]+dp[i][j+1];其中a数组表示第i棵树j位置有几个苹果。
也可以从其他任意一棵树的j+delta跳到第i棵树的j位置,所以我们应该枚举每一颗树,
dp[i][j]=max(dp[i][j],dp[q][j+delta]+a[i][j]);
3、这么一来就很明了了。第一重循环时枚举高度,从h往0递推,
第二重循环枚举当前处于哪一棵树,第三重枚举从哪一棵树转移而来,具体见代码。
#include <bits/stdc++.h>
using namespace std;
int n,h,de;
int a[5009][2009],dp[5009][2009];
int main()
{
cin>>n>>h>>de;
for(int i=1;i<=n;i++)
{
int t,zz;
scanf("%d",&t);
while(t--){
scanf("%d",&zz);
a[i][zz]++;
}
}
int maxn=0;
for(int j=h;j>=0;j--)
{
for(int i=1;i<=n;i++)
{
dp[i][j]=max(dp[i][j],a[i][j]+dp[i][j+1]);
for(int q=1;q<=n;q++)
{
if(q!=i)
dp[i][j]=max(dp[i][j],dp[q][j+delta]+a[i][j]);
}
maxn=max(maxn,dp[i][j]);
}
}
cout<<maxn;
}
但是聪明的你肯定发现了,妥妥的tle.
于是有了n^2的优化。
我们想一下,为什么要有第三重循环?我们只不过想从当前高度的状态里挑一棵最大收益的树转移过来。那这样就简单了,我们开一个pre数组保存对应高度的最大收益,转移的时候直接拿过来用就好了。
不懂的话请看代码,很容易理解。
#include <bits/stdc++.h>
using namespace std;
int n,h,de;
int a[5009][2009],dp[5009][2009],pre[5009];
int main()
{
cin>>n>>h>>de;
for(int i=1;i<=n;i++)
{
int t,zz;
scanf("%d",&t);
while(t--){
scanf("%d",&zz);
a[i][zz]++;
}
}
int maxn=0;
for(int j=h;j>=0;j--)
{
for(int i=1;i<=n;i++)
{
dp[i][j]=a[i][j]+dp[i][j+1];//先继承上一次
dp[i][j]=max(dp[i][j],pre[j+de]+a[i][j]);//转移
pre[j]=max(pre[j],dp[i][j]);//尝试更新当前的pre
maxn=max(maxn,dp[i][j]);
}
}
cout<<maxn;
}
希望管理大大能过。第一次写题解被退回来了,原因是排版不整齐。 没有备份,希望这次能过。
ps:要是觉得对你有帮助,评论一下让我知道好嘛...!?