问题 A: 取石子-----dp优化/思维/二进制压位

题目描述
n+e最近在研究取⽯⼦游戏。
有n堆⽯⼦,第i堆⽯⼦有ai个,最多取m堆⽯⼦(保证m≤n),请问在要求总⽯⼦数不超过k的情况下最多能取多少⽯⼦。
输入
第⼀⾏输⼊3个数字n,m,k,意义见上。
第⼆⾏n个数字,依次表示ai。
输出
输出⼀个数字,表示你的答案。
样例输入 Copy
4 3 5
1 1 2 3
样例输出 Copy
5
提示
取第1、2、4组⽯⼦,或3,4组⽯⼦,刚好是5个。

数据分为A、B、C三组,各占30%、30%、40%。
对于A组数据,1≤m≤n≤10,1≤k≤1000,1≤ai≤100
对于B组数据,1≤m≤n≤20,1≤k≤108,1≤ai≤106
对于C组数据,1≤m≤n≤200,1≤k≤2500,1≤ai≤50

解析:对于A组和C组数据dp就可以了。
对于B组数据,k在1e8,所以我们对n件物品压位 1<<n。
例1110001 1代表着第几堆取,0代表这第几堆不取 ((i<<n)>>k)&1。
详细看代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,k;
int f[2505][2505];
int a[1000005];
int main()
{
	scanf("%d %d %d",&n,&m,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	if(k<=2500)
	{
		for(int i=1;i<=n;i++)
			for(int j=k;j>=a[i];j--)
				for(int p=1;p<=m;p++)
					f[j][p]=max(f[j][p],f[j-a[i]][p-1]+a[i]);
		int maxv=0;
		for(int i=1;i<=m;i++) maxv=max(maxv,f[k][i]);
		cout<<maxv<<endl;
	}
	else
	{
		ll maxv=0;
		for(int i=1;i<(1<<n);i++)
		{
			int  cnt=0;ll sum=0;
			for(int j=1;j<=n;j++)
			{
				if((i>>(j-1))&1)
				{
					cnt++;
					sum+=a[j];
				}
			}
			if(cnt<=m&&sum<=k)  maxv=max(sum,maxv);
		}
		cout<<maxv<<endl;
	}
	return 0;
}

发布了284 篇原创文章 · 获赞 6 · 访问量 3775

猜你喜欢

转载自blog.csdn.net/qq_43690454/article/details/104046040