最优卡组

最优卡组

参考:【LOJ6254】最优卡组

题解

我们可以先考虑堆模拟搜索。可以先将卡包内部排序,再用卡包的最大与次大排序。

我们用一个四元组(val,x,y,z)存储状态,val即当前的卡能量值,选择前x包卡,第x包选的是第y张牌。z表示是否它由下方的第2,3情况转来。

有如下几种情况:

1.当y< c_{x},则我们可选的情况有\left ( val+...,x,y+1,0 \right )

2.当x< n,则我们可选的情况有\left ( val+...,x+1,2,1 \right )

3.当x< n,z= 1,则我们可选的情况有\left ( val+...,x+1,2,1 \right )

可以证明这样枚举不会重复或漏掉。可惜我不会

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream> 
#include<algorithm>
#include<stack>
#include<vector>
#include<queue>
#include<cstdlib>
#define node ming
using namespace std;
typedef long long LL;
const LL INF=0x3f3f3f3f;
const LL MAXN=3000010;
template<typename _T>
char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
LL rd()
{
    LL ret=0;
	char gc=getchar();
    while(!isdigit(gc)) gc=getchar();
    while(isdigit(gc))  ret=ret*10+(gc^'0'),gc=getchar();
    return ret;
}
struct ming
{
	LL val;
	int x,y;
	bool z;
	ming(){}
	ming(LL V,int X,int Y,bool Z){val=V;x=X;y=Y;z=Z;}
	bool operator < (const ming &a)const
	{
		return val<a.val;
	}
};
priority_queue<ming> q;
int n,m;
int p[MAXN],c[MAXN];
vector<LL> v[MAXN];
bool cmp1(const int &a,const int &b)
{
	return a>b;
}
bool cmp2(const int &a,const int &b)
{
	if(c[a]==1||c[b]==1) return c[a]!=1;
	return  v[a][0]-v[a][1]<v[b][0]-v[b][1];
}
char puf[100000],*p3=puf;
inline void ps(const char &x)
{
    if(p3==puf+100000)  fwrite(puf,1,100000,stdout),p3=puf;
    *p3++=x;
}
inline void flush()
{
    fwrite(puf,1,p3-puf,stdout);
}
inline void wt(LL x)
{
    static char sta[20];
    int top=0;
    if(!x)  ps('0');
    while(x)    sta[++top]=(x%10)^'0',x/=10;
    while(top)  ps(sta[top--]);
}
int main()
{
	n=rd();m=rd();
	int i,j,a,b;
	ming x=ming(0,1,0,0);
	for(i=1;i<=n;i++)
	{
		v[i].clear(),c[i]=rd(),p[i]=i;
		for(j=0;j<c[i];j++)
			v[i].push_back(rd());
		sort(v[i].begin(),v[i].end(),cmp1);
		x.val+=v[i][0];
	}
	sort(p+1,p+n+1,cmp2);
	while(c[p[n]]==1) n--;
	q.push(x);
	while(m--)
	{
		x=q.top(),q.pop(),a=x.x,b=x.y;
		wt(x.val),ps(!m?'\n':' ');
		if(b+1<c[p[a]]) q.push(ming(x.val-v[p[a]][b]+v[p[a]][b+1],a,b+1,0));
		if(a<n) q.push(ming(x.val-v[p[a+1]][0]+v[p[a+1]][1],a+1,1,1));
		if(a<n&&x.z) q.push(ming(x.val-v[p[a]][1]+v[p[a]][0]-v[p[a+1]][0]+v[p[a+1]][1],a+1,1,1));
	}
	flush();
	return 0;
}

谢谢!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值