[AT_abc118_d]题解

洛谷题目链接 & AT题目链接

思路分析:

这是一道恰好装满的完全背包问题,和正常的完全背包一样,初始化改一下即可。

这里说一下为什么 \(dp[0]\) 要赋成 \(0\)\(dp[1]\)\(dp[n]\) 要赋值成一个极小值,因为只有 \(0\) 在背包容量恰好为 \(0\) 的时候价值为 \(0\),要求最大值所以剩下的要赋成一个极小值。

然后就是一道完全背包模板题了,这道题时间复杂度应该是趋近于 \(O(nm^2)\),因为 \(m\) 很小所以几乎可以做到 \(O(n)\),那就可以用不加优化的 \(3\) 层循环来做。

代码:

#include<bits/stdc++.h>
using namespace std;
int read(){
	char ch=getchar();
	int x=0;
	bool flag=false;
	while(ch<'0'||ch>'9'){
		if(ch=='-'){
			flag=true;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+(ch-'0');
		ch=getchar();
	}
	return flag?-x:x;
}//快读
bool cmp(int x,int y){
	return x>y;
}
int n,m,dp[10003],a[15],num[15]={6,2,5,5,4,5,6,3,7,6};//我的m和n与题目中颠倒的
signed main(){
	m=read(),n=read();
  	//再说一下,我的m和n与题目中是颠倒的
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=m;i++){
		dp[i]=-0x3f3f3f3f;
	}
  	//初始化
	for(int i=1;i<=n;i++){
		for(int j=2;j<=m;j++){
			int tmp=10,cnt=a[i];
			for(int k=1;j-k*num[a[i]]>=0;k++){
				if(dp[j-k*num[a[i]]]>=0){
					dp[j]=max(dp[j],dp[j-k*num[a[i]]]*tmp+cnt);//状态转移
				} 
				cnt=cnt*10+a[i];
				tmp*=10;
			}
		}
	}
	cout<<dp[m];//输出答案
	return 0;
}
posted @ 2023-11-18 08:41  xxxalq  阅读(37)  评论(0)    收藏  举报