ABC 364

ABC 364

E - Maximum Glutton

  • 给定 (ai,bi),X,Y, 记 k 是第一个让 i=1kai>Xi=1kbi>Y 成立的位置, 你可以重排二元组,请求最大的 k.
  • 标签:二维背包,思维题,判重
  • 暴力: 记 f[j][k] 表示 suma=j,sumb=k ,最多能选几个数,有转移:

f[j][k]=max(f[ja[i]][kb[i]]+1,f[j][k])

  • 初始化全0,倒着做01二维背包即可,时间复杂度 O(NXY).
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
using namespace std;
using ll = long long;
int f[10005][10005];
int n,a[88],b[88],X,Y;
signed main(){
//	freopen("test.in","r",stdin);
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>n>>X>>Y;
	F(i,1,n) cin>>a[i]>>b[i];
	F(i,1,n) G(j,X,a[i]) G(k,Y,b[i]) f[j][k]=max(f[j-a[i]][k-b[i]]+1,f[j][k]);
	cout<<min(f[X][Y]+1,n)<<"\n";
	return 0;
} 
  • 优化:观察到 f 的值域很小只有 80, 而状态过大,我们考虑把其中一维和值域交换, 即采用交换权值法
  • g[i][j] 表示最终选 i 个数, suma=j 时最小的 sumb, 最后只需要判断什么时候 g[i][1X] 全部大于 Y 即可. 有转移:

g[i][j]=min(g[i1][ja[k]]+b[k],g[i][j])

  • 初始化所有 ginf, 但 g[0][0]=0.
  • 由于涉及到选几个数, 要做 n 次01背包, 所以即使倒着扫也无法保证不选重.
  • 解决方法是开一个 vis[N][X][N]. vis[i][j][k] 表示当 g[i[j] 最小时 k 有没有被用过,更新可以在 dp 过程中完成,复杂度仍然是对的, 详见代码。
  • 时间复杂度就变成 O(N2X) 啦!
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
using namespace std;
using ll = long long;
const int inf=0x3f3f3f3f;
int f[83][10005],psy[100005],pos[100005];
bool vis[83][10005][83];
struct node{
	int a,b;
	bool operator <(const node &o)const{
		return a==o.a?b<o.b:a<o.a;
	}
}c[88];
int n,X,Y;
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>n>>X>>Y;
	F(i,1,n) cin>>c[i].a>>c[i].b;
	sort(c+1,c+n+1);
	memset(f,0x3f,sizeof(f)); 
	f[0][0]=0; 
	F(i,1,n) {
		memset(pos,0,sizeof(pos));
		memset(psy,0,sizeof(psy));
		G(j,X,1) {
			F(k,1,n) {
				if(j<c[k].a) break;
				int tmp=f[i-1][j-c[k].a]+c[k].b;
				if(!vis[i-1][j-c[k].a][k] && f[i][j]>tmp) {
					psy[j]=j-c[k].a;
					f[i][j]=tmp;
					pos[j]=k;
				}	
			} 
		}
		F(j,1,X){
			if(psy[j]) F(k,1,n) vis[i][j][k] = vis[i-1][psy[j]][k];
			if(pos[j]) vis[i][j][pos[j]]=1;
		} 
	}
	int ans=n;
	F(i,1,n){
		bool tag=0;
		F(j,1,X) if (f[i][j]<=Y) tag=1;
		if(!tag) return cout<<i<<"\n",0;
	}
	cout<<n<<"\n";		
	return 0;
} 
posted @   superl61  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示