DP之前也是学了很久,但是中间由于学习kmp,AC自动机,树状数组,线段树,更多的把精力投入到新知识的掌握与运用,
忽视了对DP的回顾与练习,再加之有些知识点还未完全掌握,所以这次练习赛还是暴露了许多老毛病。
这次的练习赛没有模版题,都是需要自己思索才能解决的,当看到第一题的时候,有些发蒙,过了不久就转向第二题,
第二题又犯了致命的错误,跟着样例打代码,结果只过了样例。第三题更加懵了,觉得与DP没有什么联系,就往后做。
后面的题目总结来说还是思路有问题,没有往DP上想,代码能力还是很薄弱,还是要好好加强。
听了几位大佬的解析,才有些懂了。懂了还是不够,还是得努力去敲写代码去实现思想,这些题目还是要花时间好好理解。
第一题题目描述:
为了使问题简化,假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时小王站在5这个位置上,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问小王最多可能接到多少个馅饼?
思路:将馅饼掉落的时间与地点用二维数组存储,惊奇地发现这与数字三角形类似,从最底层找一条路径,使路径上的和最大。
那么状态转移方程就为f[i][j]=max(f[i+1][j],f[i+1][j+1])+pie[i][j]
pie[i][j]为时间i时掉落在位置j上的馅饼数。
第二题:codeforces 474D flowers
dp计数,再求前缀和。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int mod=1e9+7;
int dp[maxn];
int sum[maxn];
int main()
{
int n,k;
cin>>n>>k;
for(int i=0;i<=maxn;i++)
{
dp[i]=1;//初值
}
for(int i=k;i<maxn;i++)
{
dp[i]=dp[i-1]+dp[i-k];//与楼梯相似,用递归求出dp数组
dp[i]%=mod;
}
sum[0]=0;
for(int i=1;i<maxn;i++)//求前缀和
{
sum[i]=sum[i-1]+dp[i];
sum[i]%=mod;
}
for(int i=0;i<n;i++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",(sum[r]-sum[l-1]+mod)%mod);//前缀和数组求区间和
}
return 0;
}
第三题:吃水果 codeforces 363C
这道题目思路真是十分地奇妙,可以将物品转化为重量为a[i]-b[i]*k的背包,价值为a[i],所以只需要对重量为正值的做一次背包,
重量为负值的取其绝对值再做一次背包,两次相同重量的背包价值之和就是该重量下的最优值。这道题还需要细细琢磨。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=111;
int f1[maxn*maxn],f2[maxn*maxn];
int n,k,a[maxn],b[maxn],c[maxn];
int main()
{
scanf("%d %d",&n,&k);
for( int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
c[i]=a[i]-b[i]*k;//将物品转化成背包
memset(f1,-0x3f,sizeof(f1));
memset(f2,-0x3f,sizeof(f2));
f1[0]=f2[0]=0;//初值为0
for(int i=1;i<=n;i++)//正值的背包
if(c[i]>=0)
for(int j=10000;j>=c[i];j--)//10000应该是n*a[1...n]的最大值
f1[j]=max(f1[j-c[i]]+a[i],f1[j]);
for(int i=1;i<=n;i++)//负值的背包
if(c[i]<0)
{
c[i]=-c[i];
for(int j=10000;j>=c[i];j--)
f2[j]=max(f2[j-c[i]]+a[i],f2[j]);
}
int ans=-1;//不满足条件,输出-1
for(int i=0;i<=10000;i++)
{
if(f1[i]==0 && f2[i]==0)
continue;
ans=max(ans,f1[i]+f2[i]);//两个背包的最优值之和就是当前重量的最佳收益
}
printf("%d\n",ans);
return 0;
}
后面的一些题目还需要好好理解,所以先留个坑。
第六题:完美子串 codeforces 432D
这是kmp的套路题,只能说我对next数组的理解还不够深入,还是需要好好理解kmp中next数组的含义。
第七题:树的重心调整 codeforces 709E
一道非常复杂的树形DP题,还是需要好好理解并总结的。
比较匆忙的写了这篇博客,在后期会逐渐地补充,海涵。