!CodeForces 543A Writing Code --DP--(三维dp,滚动数组)

题意:n个程序员一起写m行代码,第i个程序员每写一行有a[i]个bug,求总bug不超过b的分配方案有多少种

分析:这题很像完全背包,不过求的不是最大/最小bug数,求的是bug数小于上限的分配方案。所以这题要用三维dp

dp[i][j][k]表示前i个个程序员总共写了j行代码产生了k个bug时的plan数,这题有两种转移:1)第i个程序员再写一行;2)换第i+1号程序员写

所以方程:dp[i][j][k]=dp[i-1][j][k]+dp[i][j-1][k-a[i]],注意:程序员可能一行都没写

另外三维的数组会超内存,所以用滚动数组。滚动数组主要用于递推和dp,它正是利用了递推和dp的特性,原理是这样的:比如dp[i]=dp[i-1],也就是要求dp[i]只需要dp[i-1]的信息,所以前面的dp[i-k](k>1)的信息对于dp[i]来说都是没用的,滚动的意思就是不断把前面没用的信息用后面求出的有用的信息覆盖,节约空间。具体做法就是,dp[i]需要多少前面的信息就信息数加 一那么大的数组,比如dp[i][k]=dp[i-1][k]+dp[i-2][k],0<i<10000000,0<k<10,只需dp[3][11],方程改为:

dp[i%3]=dp[(i-1)%3][k]+dp[(i-2)%3][k]即可,还有另一种滚动数组的实现方法我还没懂,先把代码放在这。

注意理解这题跟完全背包和01背包的区别和联系

代码1:

#include<iostream>
using namespace std;
long long mod,dp[2][508][508];
int a[501];
int n,m,b;
int main()
{
        cin>>n>>m>>b>>mod;
		for(int i=1;i<=n;i++) cin>>a[i];
		for(int i=1;i<=n;i++) dp[i%2][0][0]=1;
		for(int i=1;i<=n;i++)
		   for(int j=1;j<=m;j++)
		      for(int k=0;k<=b;k++){
		         if(a[i]>k)  dp[i%2][j][k]=(dp[(i-1)%2][j][k])%mod;
		      	 else  dp[i%2][j][k]=(dp[(i-1)%2][j][k]+dp[i%2][j-1][k-a[i]])%mod;
		      }
		long long ans=0;
		for(int i=0;i<=b;i++) ans=(ans+dp[n%2][m][i])%mod;
		cout<<ans%mod<<endl;
}

代码2:

#include<iostream>
#include<cstring>
using namespace std;
long long mod,dp[508][508];
int a[501];
int n,m,b;
int main()
{
	while(cin>>n>>m>>b>>mod){
		for(int i=1;i<=n;i++) cin>>a[i];
		memset(dp,0,sizeof(dp));
		for(int i=0;i<=b;i++) dp[0][i]=1;
		for(int i=1;i<=n;i++)
		   for(int j=1;j<=m;j++)
		      for(int k=a[i];k<=b;k++){
		      	   dp[j][k]=(dp[j][k]+dp[j-1][k-a[i]])%mod;
		      }
		long long ans=0;cout<<dp[m][b]<<endl;
	}
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值